井字游戏:评估节点的启发式值

Tic Tac Toe: Evaluating Heuristic Value of a Node

本文关键字:启发式 节点 评估 游戏      更新时间:2023-10-16

如果这个问题已经存在,请原谅我,我已经搜索了很多,但我没有得到我想问的问题的答案。所以,基本上,我正在尝试实现一个井字游戏AI,它使用Minimax算法来移动。

但是,我不明白的一件事是,当在空板上使用 Minimax 时,返回的值始终为 0(这是有道理的,因为如果两个玩家都以最佳状态运行,游戏总是以平局结束(。

因此,当 AI 为 X 时,Minimax 始终选择第一个磁贴作为最佳移动(因为所有移动都返回 0 作为值(。第二步也会发生同样的情况,它总是选择第二个磁贴。如何解决此问题以使我的AI选择获胜概率更高的移动?这是我使用的评估和最小最大值函数(使用 Alpha-Beta 修剪(:

int evaluate(char board[3][3], char AI)
{
for (int row = 0; row<3; row++)
{
if (board[row][0] != '_' && board[row][0] == board[row][1] && board[row][1] == board[row][2])
{
if (board[row][0]==AI)
{
return +10;
}
else
{
return -10;
}
}
}
for (int col = 0; col<3; col++)
{
if (board[0][col] != '_' && board[0][col] == board[1][col] && board[1][col] == board[2][col])
{
if (board[0][col]==AI)
{
return +10;
}
else
{
return -10;
}
}
}
if (board[1][1] != '_' && ((board[0][0]==board[1][1] && board[1][1]==board[2][2]) || (board[0][2]==board[1][1] && board[1][1]==board[2][0])))
{
if (board[1][1]==AI)
{
return +10;
}
else
{
return -10;
}
}
return 0;
}
int Minimax(char board[3][3], bool AITurn, char AI, char Player, int depth, int alpha, int beta)
{
bool breakout = false;
int score = evaluate(board, AI);
if(score == 10)
{
return score - depth;
}
else if(score == -10)
{
return score + depth;
}
else if(NoTilesEmpty(board))
{
return 0;
}
if(AITurn == true)
{
int bestvalue = -1024;
for(int i = 0; i < 3; i++)
{
for(int j = 0; j<3; j++)
{
if(board[i][j] == '_')
{
board[i][j] = AI;
bestvalue = max(bestvalue, Minimax(board, false, AI, Player, depth+1, alpha, beta));
alpha = max(bestvalue, alpha);
board[i][j] = '_';
if(beta <= alpha)
{
breakout = true;
break;
}
}
}
if(breakout == true)
{
break;
}
}
return bestvalue;
}
else if(AITurn == false)
{
int bestvalue = +1024;
for(int i = 0; i < 3; i++)
{
for(int j = 0; j<3; j++)
{
if(board[i][j] == '_')
{
board[i][j] = Player;
bestvalue = min(bestvalue, Minimax(board, true, AI, Player, depth+1, alpha, beta));
beta = min(bestvalue, beta);
board[i][j] = '_';
if(beta <= alpha)
{
breakout = true;
break;
}
}
}
if(breakout == true)
{
break;
}
}
return bestvalue;
}
}

Minimax假设最佳游戏,因此最大化"获胜概率"不是一个有意义的概念:由于其他玩家可以强制平局但不能强制获胜,因此他们将始终强制平局。如果你想与一个不完全理性的玩家进行最佳比赛(当然,这是获胜的仅有的两种方式之一*(,你需要假设对手的动作有一些概率分布,并使用类似ExpectMinimax的东西,其中有一定概率对手的动作被随机错误覆盖。或者,您可以故意限制最小最大值搜索的层数,对超过一定深度的对手游戏使用启发式方法(但仍在游戏树中搜索您自己的动作(。

 *另一个是不玩。

将代码组织到较小的例程中,使其看起来更整洁且更易于调试。除了递归最小值函数之外,一个所有可能的有效移动生成函数和一个健壮的求值子例程是必不可少的(这里似乎缺乏(。

例如,在游戏开始时,评估算法应该返回一个非零分,每个位置都应该有一个相对得分指数(例如中间位置的权重可能略高于角球(。

您的最小最大边界条件 - 如果没有空单元格位置,则返回 ; 是有缺陷的,因为即使在前一层发生输赢移动时,它也会进行评估。在更复杂的AI游戏中,这种情况将加剧。

如果你是minimax的新手,你可以在Codereview上找到很多准备好编译的示例代码。