我为一个井字游戏实现了带有alpha-beta修剪的minimax。这是代码:
如果还有更多移动,则此函数返回。
bool isMovesLeft()
{
for (int x = 0; x < ROWS; x++)
for (int y = 0; y < COLS; y++)
if (game.Board[x][y] == EMPTY)
return true;
return false;
}
评估板并返回分数。可能的结果:-10,0,10。
int evaluateBoard()
{
for (int x = 0; x < ROWS; x++)
{
if (game.Board[x][0] == game.Board[x][1] &&
game.Board[x][1] == game.Board[x][2])
{
if (game.Board[x][0] == PLAYER_X)
return 10;
else if (game.Board[x][0] == PLAYER_O)
return -10;
}
}
for (int y = 0; y < COLS; y++)
{
if (game.Board[0][y] == game.Board[1][y] &&
game.Board[1][y] == game.Board[2][y])
{
if (game.Board[0][y] == PLAYER_X)
return 10;
else if (game.Board[0][y] == PLAYER_O)
return -10;
}
}
if (game.Board[0][0] == game.Board[1][1] &&
game.Board[1][1] == game.Board[2][2])
{
if (game.Board[0][0] == PLAYER_X)
return 10;
else if (game.Board[0][0] == PLAYER_O)
return -10;
}
if (game.Board[0][2] == game.Board[1][1] &&
game.Board[1][1] == game.Board[2][0])
{
if (game.Board[0][2] == PLAYER_X)
return 10;
else if (game.Board[0][2] == PLAYER_O)
return -10;
}
return 0;
}
具有alpha-beta剪枝的实际最小极大算法:
int minimax(int depth, int alpha, int beta, bool isMax)
{
int score = evaluateBoard();
if (score == 10)
return 10 - depth;
if (score == -10)
return -10 + depth;
if (!isMovesLeft())
return 0;
if (isMax)
{
int best = -1000;
for (int x = 0; x < ROWS; x++)
{
for (int y = 0; y < COLS; y++)
{
if (game.Board[x][y] == EMPTY)
{
game.Board[x][y] = PLAYER_X;
int max = minimax(depth + 1, alpha, beta, !isMax);
if (max > best)
best = max;
if (best > alpha)
alpha = best;
game.Board[x][y] = EMPTY;
if (beta <= alpha)
break;
}
}
}
return best;
}
else if (!isMax)
{
int best = 1000;
for (int x = 0; x < ROWS; x++)
{
for (int y = 0; y < COLS; y++)
{
if (game.Board[x][y] == EMPTY)
{
game.Board[x][y] = PLAYER_O;
int min = minimax(depth + 1,alpha, beta, isMax);
if (min < best)
best = min;
if (best < beta)
beta = best;
game.Board[x][y] = EMPTY;
if (beta <= alpha)
break;
}
}
}
return best;
}
}
返回最佳移动。轮到对手时调用。
BestMove findBestMove()
{
int bestScore = -1000;
BestMove bestMove;
bestMove.Row = -1;
bestMove.Col = -1;
if (game.Board[1][1] == EMPTY)
{
bestMove.Row = 1;
bestMove.Col = 1;
return bestMove;
}
for (int x = 0; x < ROWS; x++)
{
for (int y = 0; y < COLS; y++)
{
if (game.Board[x][y] == EMPTY)
{
game.Board[x][y] = PLAYER_X;
int score = minimax(0, -10000000000, 10000000000, false);
game.Board[x][y] = EMPTY;
if (score > bestScore)
{
bestScore = score;
bestMove.Row = x;
bestMove.Col = y;
}
}
}
}
return bestMove;
}
我还在计算分数时增加了深度(在< code>minimax函数中),使人工智能稍微更加智能。
然而,人工智能仍然会做出愚蠢的动作,而且很容易被击败。有些胜利一次又一次地重复。
上面的代码是否正确还是我错过了什么?
问题是由isMax
的错误值引起的。在最小化
函数的主else
块中,递归调用是通过传递isMax
进行的,但这意味着递归调用将获得与当前调用相同的isMax
值。这是错误的。它应该切换该值。要么传递! isMax
,要么只传递一个硬编码的true
,因为这里isMax
是false
。