Javascript 为什么我的minimax算法是dosen';不要阻止我的行动?
这是我的Tic-Tac-Toe算法的Javascript代码:Javascript 为什么我的minimax算法是dosen';不要阻止我的行动?,javascript,algorithm,minimax,Javascript,Algorithm,Minimax,这是我的Tic-Tac-Toe算法的Javascript代码: function minimax(newGrid, depth, Player){ //debugger const gameState = checkWin(newGrid,true); if (gameState == false){ values = []; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) {
function minimax(newGrid, depth, Player){
//debugger
const gameState = checkWin(newGrid,true);
if (gameState == false){
values = [];
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
const boardCopy = _.cloneDeep(newGrid);
if (boardCopy[i][j] !== '') continue;
boardCopy[i][j] = Player;
console.log(boardCopy);
const value = minimax(boardCopy, depth + 1, (Player === PLYR_TOKEN) ? COMP_TOKEN : PLYR_TOKEN);
values.push({
cost: value,
cell: {
i: i,
j: j
}
});
}
}
//debugger
if (Player === COMP_TOKEN){
const max = _.maxBy(values, (v) => {
return v.cost;
});
if( depth === 0 ){
return max.cell;
} else {
return max.cost;
}
}else{
const min = _.minBy(values, (v) => {
return v.cost;
});
if( depth === 0 ){
return min.cell;
} else {
return min.cost;
}
}
} else if (gameState === null){
return 0;
} else if (gameState === PLYR_TOKEN){
return depth - 10;
} else if (gameState === COMP_TOKEN){
return 10 - depth;
}
}
正常情况下,一个完美的极大极小算法应该选择这个选项来阻止我获胜(小写o是新的动作):
问题是,我的代码中包含以下内容(小写字母o表示新的移动):
为什么??我不知道,但我认为它会抓住任何获胜的机会,忽略我的动作,忽略我离胜利还有一步的事实。
老实说,我真的不明白这个算法是如何工作的
其他信息:主板是一个二维数组,minimax函数的结果是一个具有两个属性(i,j)的对象,表示主板上的坐标
const board = [
['','',''],
['','',''],
['','','']
];
因此,当有疑问时,请发表评论!我一步一步地做,当我陷入困境时,我并没有停下来,而是在每次我理解更多的东西时,我都会拖延和来回
//newGrid : the board
//depth : keep track of the "guessing level"
//Player : keep track of who's turn it would be
function minimax(newGrid, depth, Player){
//checking if the game ended
const gameState = checkWin(newGrid,true);
//if not
if (gameState == false){
values = [];
//for each cell in the grid
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
//we make a deep copy of the board
const boardCopy = _.cloneDeep(newGrid);
//if the cell isn't empty, we jump to the next one
if (boardCopy[i][j] !== '') continue;
//here we assign the Player to the cell (simulating a move from this player to this cell)
boardCopy[i][j] = Player;
//debugging
console.log(boardCopy);
//here go some recursivity, so we're putting our deepcopy with the simulated move, adding a depth level, and switching player
const value = minimax(boardCopy, depth + 1, (Player === PLYR_TOKEN) ? COMP_TOKEN : PLYR_TOKEN);
//since it was a recursive thing, please do imagine we get here at max depth BEFORE lesser depths, and then we'll climb back when each depth return its value to the previous one
//so here the first "value" going in "values" will be the first cell where we did not go through "if (gameState == false){" : first cell where the game ended (with its associated cost, more on that later)
values.push({
cost: value,
cell: {
i: i,
j: j
}
});
}
}
//when the loop ended
//if we're simulating a computer turn
if (Player === COMP_TOKEN){
//getting the "value" with max cost out of "values"
const max = _.maxBy(values, (v) => {
return v.cost;
});
//if we endend our recursivity (we climbed all the way back to depth 0) == we are on the actual grid with no simulation
if( depth === 0 ){
return max.cell; //return the cell (computer will play this cell)
} else {
return max.cost; //else return the cost (to put in the "values" list)
}
}else{ //if we're simulating a player turn, same thing but with the min
const min = _.minBy(values, (v) => {
return v.cost;
});
if( depth === 0 ){ //may not be useful if you always call minimax at depth 0 on computer turn
return min.cell;
} else {
return min.cost;
}
}
} else if (gameState === null){ //so, here we're simulating our endgame, a draw have a value of 0
return 0;
} else if (gameState === PLYR_TOKEN){ //a player win have a value of "depth-10" (the quicker he win, the lesser the result)
return depth - 10;
} else if (gameState === COMP_TOKEN){ //a computer win have a value of "10-depth" (the quicker he win, the greater the result)
return 10 - depth;
}
}
这还远远不够完美(比如说,你可以用两步赢下他),也没有经过测试,但我希望现在对你来说更清楚。
当你完成了你的代码,并且它按照你想要的方式工作时,请毫不犹豫地发布它,以获得优化建议。添加更多关于问题的详细信息,这是一款什么样的游戏。对不起,我没有意识到,谢谢。这是关于井字游戏的,我刚在帖子里加上。这个问题真的不清楚。“它不会阻止我的移动”是什么意思?为什么算法“抓住任何获胜的机会”会很奇怪?具体来说,有什么事情没有按您期望的方式工作?这是我第一次发布问题,谢谢您的建议,我试图更清楚地说明我的问题/解释。感谢您的回答和注释代码中的所有行,我以前没有意识到,但注释确实有助于理解发生了什么。
X - O
- X o
- - -
const board = [
['','',''],
['','',''],
['','','']
];
//newGrid : the board
//depth : keep track of the "guessing level"
//Player : keep track of who's turn it would be
function minimax(newGrid, depth, Player){
//checking if the game ended
const gameState = checkWin(newGrid,true);
//if not
if (gameState == false){
values = [];
//for each cell in the grid
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
//we make a deep copy of the board
const boardCopy = _.cloneDeep(newGrid);
//if the cell isn't empty, we jump to the next one
if (boardCopy[i][j] !== '') continue;
//here we assign the Player to the cell (simulating a move from this player to this cell)
boardCopy[i][j] = Player;
//debugging
console.log(boardCopy);
//here go some recursivity, so we're putting our deepcopy with the simulated move, adding a depth level, and switching player
const value = minimax(boardCopy, depth + 1, (Player === PLYR_TOKEN) ? COMP_TOKEN : PLYR_TOKEN);
//since it was a recursive thing, please do imagine we get here at max depth BEFORE lesser depths, and then we'll climb back when each depth return its value to the previous one
//so here the first "value" going in "values" will be the first cell where we did not go through "if (gameState == false){" : first cell where the game ended (with its associated cost, more on that later)
values.push({
cost: value,
cell: {
i: i,
j: j
}
});
}
}
//when the loop ended
//if we're simulating a computer turn
if (Player === COMP_TOKEN){
//getting the "value" with max cost out of "values"
const max = _.maxBy(values, (v) => {
return v.cost;
});
//if we endend our recursivity (we climbed all the way back to depth 0) == we are on the actual grid with no simulation
if( depth === 0 ){
return max.cell; //return the cell (computer will play this cell)
} else {
return max.cost; //else return the cost (to put in the "values" list)
}
}else{ //if we're simulating a player turn, same thing but with the min
const min = _.minBy(values, (v) => {
return v.cost;
});
if( depth === 0 ){ //may not be useful if you always call minimax at depth 0 on computer turn
return min.cell;
} else {
return min.cost;
}
}
} else if (gameState === null){ //so, here we're simulating our endgame, a draw have a value of 0
return 0;
} else if (gameState === PLYR_TOKEN){ //a player win have a value of "depth-10" (the quicker he win, the lesser the result)
return depth - 10;
} else if (gameState === COMP_TOKEN){ //a computer win have a value of "10-depth" (the quicker he win, the greater the result)
return 10 - depth;
}
}
if (Player === COMP_TOKEN){
//[...]
//if we endend our recursivity (we climbed all the way back to depth 0) == we are on the actual grid with no simulation
if( depth === 0 ){
const min = _.minBy(values, (v) => {
return v.cost;
});
if(min.cost>=-9)return min.cell; //if player win in the next turn, prevent it instead
else return max.cell; //else return the best cell for computer
}
//[...]