【发布时间】:2021-08-02 23:35:39
【问题描述】:
我遇到了一个问题,即 AI 玩家总是先玩它遇到的第一个可用动作。我试图让 AI 与 Minimax 算法一起工作。你觉得我能怎么解决?
这是代码(带解释):
展示代码前的一点见解:
- 我试图以这样一种方式进行设置,即 AI 播放器(无论它是什么颜色)是最大化播放器。所以如果玩家回合是白人,但白人是AI玩家,那么isMaximizing = true。
- 我想指出这一点,这样玩家在颜色方面的回合和玩家在最大化方面的回合不会混淆。
我最初使用它的地方:
// AI Hard - Return Minimax
function minimaxAI(){
// Here's where the minimax function is initially called
const AI = (ourPlayer === "white") ? "black" : "white"
const squares = history[history.length - 1].slice()
// AI is the maximizing player so we get -Infinity, it'll try to increase the value of bestScore
let bestScore = -Infinity
let bestMove = null
// Perform minimax algorithm for each valid move and pick the best score
// Get the valid moves for the AI player
const AIValidMoves = checkSquaresForSides()[(AI === "black") ? 0 : 1 ]
for (var AIMove=0;AIMove<AIValidMoves.length;AIMove++){
// Play the AI moves and generate the new board
const crds = AIValidMoves[AIMove].turned
crds.unshift(AIValidMoves[AIMove].coordinates)
const newBoard = handleMove(crds, squares,AI,false,false)
// Check minimax for the new board
const score = minimax(newBoard,4,false)
// If score is higher than the current one, replace the highest score and the according coordinates
if (score > bestScore || AIMove === 0) {
bestScore = score
bestMove = crds
}
}
console.log('Final Value:')
console.log(bestScore)
// Play the move(this time on the real board)
const upcomingAI = handleMove(bestMove)
// Set it as the latest of the collection of squares
setHistory(upcomingAI)
// Useless to know for this issue
setStepNumber(upcomingAI.length - 1)
}
极小极大算法本身:
function minimax(board, depth, isMaximizing) {
const AI = (ourPlayer === "white") ? "black" : "white"
const stones = setStoneCount(board)
// If there's a winner, return Infinity, 0 or -Infinity depending on whether AI won, it is a tie or our player won
if (stones[0] === 0 || stones[1] === 0 || stones[0] + stones[1] === 64) {
// Return the score of the move if the game is over
let score = (stones[(AI === "black") ? 1 : 0] === 0) ? Infinity : (stones[stones[0] === stones[1]]) ? 0 : -Infinity
return score
} else if (depth === 0) {
// If the maximal depth is reached, then evaluate the current board by counting all the stones for the both sides and subtracting one from the other appropriately
const squares = setStoneCount(board)
let score = 0
if (AI === "black") {
score = squares[0] - squares[1]
} else if (AI === "white") {
score = squares[1] - squares[0]
}
return score
}
if (isMaximizing) {
// Perform minimax if depth !== 0 and isMaximizing, just like we did initially
let bestScore = -Infinity
// Get the valid moves for the maximizing player
const AIValidMoves = checkSquaresForSides()[(AI === "black") ? 0 : 1 ] // AI Moves because isMaximizing = true
for (var AIMove=0;AIMove<AIValidMoves.length;AIMove++){
const crds = AIValidMoves[AIMove].turned
crds.unshift(AIValidMoves[AIMove].coordinates)
const newBoard = handleMove(crds,board,AI,false,false)
// check for isMaximizing
let maximizingNext = !isMaximizing
// If there's no move to make for the one side, player turn might stay the same. Here, I check for those situations
const available = checkSquaresForSides(newBoard)
if (available[0].length === 0) {
if (AI === "white") {
maximizingNext = true
} else {
maximizingNext = false
}
} else if (available[1].length === 0){
if (AI === "black") {
maximizingNext = true
} else {
maximizingNext = false
}
}
// Perform minimax for the new board(depth is one less)
const score = minimax(newBoard,depth - 1,maximizingNext)
// If current score is higher than the highest one caught yet, it should be replaced
if (score > bestScore) {
bestScore = score
}
}
return bestScore
} else {
// Perform minimax if depth !== 0 and isMaximizing
let bestScore = Infinity
// Get the valid squares for the minimizing player
const PlayerValidMoves = checkSquaresForSides()[(AI === "black") ? 1 : 0 ] // Player Moves because isMaximizing = false
// Play each move one-by-one for the minimizing player
for (var playerMove=0;playerMove<PlayerValidMoves.length;playerMove++) {
const crds = PlayerValidMoves[playerMove].turned
crds.unshift(PlayerValidMoves[playerMove].coordinates)
const newBoard = handleMove(crds,board,ourPlayer,false,false)
// check for isMaximizing
let maximizingNext = !isMaximizing
// Just like the previous one, check whether there's an exceptional situation to be considered with the player turn
const available = checkSquaresForSides(newBoard)
if (available[0].length === 0) {
if (AI === "white") {
maximizingNext = true
} else {
maximizingNext = false
}
} else if (available[1].length === 0){
if (AI === "black") {
maximizingNext = true
} else {
maximizingNext = false
}
}
// Perform minimax for the new board
const score = minimax(newBoard,depth - 1,maximizingNext)
// If the current score is lower than the lowest one obtained so far, it should be replaced
if (score < bestScore) {
bestScore = score
}
}
return bestScore
}
}
它最初确实有效,但是当我对达到深度时评估板的方式不满意时。我改了,现在不行了。我不想回到前一个,因为它不准确。但是,为什么 AI 玩家会先走它遇到的第一步,但没有正确评估呢?
【问题讨论】:
标签: javascript reactjs minimax