Casi he completado la lógica de mi minimax de tres en raya y funciona bastante bien. Pero sigo encontrando algunos movimientos diagonales en los que la IA aparentemente se equivoca. Por ejemplo, si juegas al cuadrado 3, 6, 5 y 7, ganarás. No bloquea la esquina inferior por alguna razón.
Aquí está la llamada minimax obteniendo recursivamente la mejor puntuación que nuestra computadora puede hacer:
let compMove; let bestScore = -Infinity; for (let i = 0; i < 9; i++) { if (gameBoard.array[i] == '') { gameBoard.array[i] = 'X'; let score = minimax(gameBoard.array, 0, true); gameBoard.array[i] = ''; if (score > bestScore) { bestScore = score; compMove = i; } } }Aquí está la función minimax real en sí:
let scores = { X: 10, O: -10, tie: 0 } const minimax = (board, depth, maximizingPlayer) => { let result = checkWinner(gameBoard.currentPlayer); if (result !== null) { return scores[result]; } if (maximizingPlayer) { let bestScore = -Infinity; for (let i = 0; i < 9; i++) { if (board[i] == '') { board[i] = 'O'; let score = minimax(board, depth + 1, true); board[i] = ''; if (score > bestScore) { bestScore = score; } } } return bestScore; } else { let bestScore = Infinity; for (let i = 0; i < 9; i++) { if (board[i] == '') { board[i] = 'X'; let score = minimax(board, depth + 1, false); board[i] = ''; if (score < bestScore) { bestScore = score; } } } return bestScore; } }Si algo se le ocurre a alguien, se lo agradecería mucho. ¡Estoy perplejo!
Si desea probar el estado actual del juego, aquí está el codepen:
Hay estos problemas:
Como la "computadora" juega con "O", el código donde configuraste compMove no debe moverse con "X", sino con "O". Entonces, el primer bloque de código que tienes en tu publicación debería ser:
let compMove; let bestScore = Infinity; // <-- to minimize (positive) for (let i = 0; i < 9; i++) { if (gameBoard.array[i] == '') { gameBoard.array[i] = 'O'; // <-- not X let score = minimax(gameBoard.array, 0, true); gameBoard.array[i] = ''; if (score < bestScore) { // <-- minimize bestScore = score; compMove = i; } } } checkWinner(gameBoard.currentPlayer) siempre verifica una victoria para el mismo jugador, ya que gameBoard.currentPlayer no se modifica durante la búsqueda minimax. Entonces esto perderá victorias para el oponente. De hecho, dejaría gameBoard.currentPlayer solo y pasaría un argumento que se basa en el argumento maximizingPlayer :
let result = checkWinner("XO"[+maximizingPlayer]); // dynamically determine player Siempre pasa el valor actual de maximizingPlayer a la llamada recursiva. Cuando es falso, pasa falso, y cuando es verdadero, pasa verdadero. Esto significa que nunca cambia (ver el siguiente punto).
Al maximizar el puntaje, su código permite que "O" haga movimientos, pero ese es el jugador que minimiza. Así que eso necesita ser cambiado.
const minimax = (board, depth, maximizingPlayer) => { let result = checkWinner("XO"[+maximizingPlayer]); // <-- if (result !== null) { return scores[result]; } let bestMove; if (maximizingPlayer) { let bestScore = -Infinity; for (let i = 0; i < 9; i++) { if (board[i] == '') { board[i] = 'X'; // <-- let score = minimax(board, depth + 1, false); // <-- board[i] = ''; if (score > bestScore) { bestMove = i; bestScore = score; } } } return bestScore; } else { let bestScore = Infinity; for (let i = 0; i < 9; i++) { if (board[i] == '') { board[i] = 'O'; // <-- let score = minimax(board, depth + 1, true); // <-- board[i] = ''; if (score < bestScore) { bestMove = i; bestScore = score; } } } return bestScore; } }Con esos cambios funcionará.
Comentario final: es una pena que en su código tenga al menos tres conceptos que corresponden a la noción de "jugador": maximizingPlayer es un booleano, Player es un objeto con un miembro del team , currentPlayer es una propiedad de carácter y el player el argumento también es el personaje. Esto debería armonizarse. Ciertamente, la propiedad currentPlayer apenas sirve para ningún propósito. Simplemente se establece aquí y allá en una "X" u "O" codificada y luego se pasa inmediatamente como argumento.