tic-tac-toe中的Minimax未正确评分分支
我正在尝试用C语言创建一个完美的井字游戏。我使用2D数组来跟踪棋盘 我已经将问题缩小到了我的tic-tac-toe中的Minimax未正确评分分支,c,algorithm,tic-tac-toe,minimax,C,Algorithm,Tic Tac Toe,Minimax,我正在尝试用C语言创建一个完美的井字游戏。我使用2D数组来跟踪棋盘 我已经将问题缩小到了我的minimax函数对每个潜在动作的评分方式,但是我在调试它时遇到了困难,因为错误通常发生在第二个动作附近,并且我无法从那一点跟踪所有潜在的游戏状态 计算机在第一位,并且总是“X”minimax是从computerMove函数中调用的,该函数尝试每个可用的移动,然后将其最小化。它将从minimax中为潜在游戏状态返回的值作为临时分数,并将其与当前最高分数进行比较。我相信该计划的一部分正在发挥作用。问题在于m
minimax
函数对每个潜在动作的评分方式,但是我在调试它时遇到了困难,因为错误通常发生在第二个动作附近,并且我无法从那一点跟踪所有潜在的游戏状态
计算机在第一位,并且总是“X”minimax
是从computerMove
函数中调用的,该函数尝试每个可用的移动,然后将其最小化。它将从minimax
中为潜在游戏状态返回的值作为临时分数,并将其与当前最高分数进行比较。我相信该计划的一部分正在发挥作用。问题在于minimax
函数本身
以下是我的代码的重要部分:
int minimax(char board[][3], char maxPlayer) // +10 -> X wins
{ // -10 -> O wins
char minPlayer; // 0 -> draw
int scores[3][3];
if (maxPlayer == 'X') minPlayer = 'O';
else minPlayer = 'X';
int topScore = 0;
// initializing scores to ensure a move is selected
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
scores[i][j] = -11;
}
}
// check for terminal state
if (isWinning(board,'X') || isWinning(board,'O') ||
!moveAvailable(board)) {
if (isWinning(board,'X')) return 10;
else if (isWinning(board,'O')) return -10;
else return 0;
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (board[i][j] == 'U') {
board[i][j] = maxPlayer; // try the move
scores[i][j] = minimax(board,minPlayer);// minimax it
board[i][j] = 'U'; // undo the move
}
}
}
// if calling minimax for computer, maximize the score
if (maxPlayer == 'X') {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (scores[i][j] > topScore && scores[i][j] != -11)
topScore = scores[i][j];
}
}
}
// if calling minimax for human, minimize the score
else if (maxPlayer == 'O') {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (scores[i][j] < topScore && scores[i][j] != -11)
topScore = scores[i][j];
}
}
}
return topScore;
}
int minimax(char board[][3],char maxPlayer)//+10->X赢
{//-10->O获胜
char minPlayer;//0->draw
智力分数[3][3];
如果(maxPlayer='X')minPlayer='O';
else minPlayer='X';
int-topScore=0;
//初始化分数以确保选择移动
对于(int i=0;i<3;i++){
对于(int j=0;j<3;j++){
[i][j]=-11分;
}
}
//检查终端状态
如果(是赢的(板,'X')|是赢的(板,'O')|
!可用(板)){
如果(iswing(board,'X'))返回10;
否则如果(正在获胜(板,'O'))返回-10;
否则返回0;
}
对于(int i=0;i<3;i++){
对于(int j=0;j<3;j++){
如果(板[i][j]=='U'){
board[i][j]=maxPlayer;//尝试移动
分数[i][j]=minimax(棋盘,minPlayer);//minimax it
板[i][j]=“U”;//撤消移动
}
}
}
//如果为计算机调用minimax,则将分数最大化
如果(maxPlayer='X'){
对于(int i=0;i<3;i++){
对于(int j=0;j<3;j++){
如果(得分[i][j]>上核和得分[i][j]!=-11)
topScore=得分[i][j];
}
}
}
//如果为人调用minimax,则最小化分数
else if(maxPlayer='O'){
对于(int i=0;i<3;i++){
对于(int j=0;j<3;j++){
如果(得分[i][j]<上核和得分[i][j]!=-11)
topScore=得分[i][j];
}
}
}
返回上堆芯;
}
问题在于topScore
初始化:
- 你应该在11点或-11点初始化
,这取决于谁打球,而不是0,否则两名球员都会认为他们至少可以从深度2开始打到平局(事实并非如此)topScore
- 就良好实践(imho)而言,我认为应该将最后两个循环归为一个循环,在更新
之前,将topScore
条件放在其中。此外,您应该跳过if(maxPlayer='X')
,比在分数中查找板[i][j]!='U'
更容易理解(尽管这很好)-11
if(board[i][j]='U'){
这个条件从来都不是真的,我猜这一行:得分[row][column]=-11;//将all设置为“O”wins
不正确。根据函数签名语句上的其他注释,“O”wins为-10,而不是-11每个递归都以新的未初始化版本的分数[]开始
这可能是不正确的。分数值从来都不是0、-11和+10。我认为分数应该是累加的。也就是说,将每个新的分数初始化为全部0,然后每次递归调用minimax()
都会导致上层分数增加(可能增加-10)根据对minimax()
@VidorVistrom的递归调用的结果,我猜董事会最初包含了我们所有人,所以他确实需要这个检查。