gpt4 book ai didi

c++ - Negamax 实现似乎不适用于井字游戏

转载 作者:太空狗 更新时间:2023-10-29 23:07:34 26 4
gpt4 key购买 nike

我已经实现了 Negamax,因为它可以在 wikipedia 上找到,其中包括 alpha/beta 剪枝。

但是,它似乎倾向于失败的一步,据我所知这是无效的结果。

这款游戏是井字游戏,我已经抽象了大部分游戏玩法,因此应该很容易发现算法中的错误。

#include <list>
#include <climits>
#include <iostream>

//#define DEBUG 1

using namespace std;

struct Move {
int row, col;

Move(int row, int col) : row(row), col(col) { }
Move(const Move& m) { row = m.row; col = m.col; }
};

struct Board {
char player;
char opponent;
char board[3][3];

Board() { }

void read(istream& stream) {
stream >> player;
opponent = player == 'X' ? 'O' : 'X';

for(int row = 0; row < 3; row++) {
for(int col = 0; col < 3; col++) {
char playa;

stream >> playa;
board[row][col] = playa == '_' ? 0 : playa == player ? 1 : -1;
}
}
}

void print(ostream& stream) {
for(int row = 0; row < 3; row++) {
for(int col = 0; col < 3; col++) {
switch(board[row][col]) {
case -1:
stream << opponent;
break;

case 0:
stream << '_';
break;

case 1:
stream << player;
break;

}
}
stream << endl;
}
}

void do_move(const Move& move, int player) {
board[move.row][move.col] = player;
}

void undo_move(const Move& move) {
board[move.row][move.col] = 0;
}

bool isWon() {
if (board[0][0] != 0) {
if (board[0][0] == board[0][1] &&
board[0][1] == board[0][2])
return true;

if (board[0][0] == board[1][0] &&
board[1][0] == board[2][0])
return true;
}

if (board[2][2] != 0) {
if (board[2][0] == board[2][1] &&
board[2][1] == board[2][2])
return true;

if (board[0][2] == board[1][2] &&
board[1][2] == board[2][2])
return true;
}

if (board[1][1] != 0) {
if (board[0][1] == board[1][1] &&
board[1][1] == board[2][1])
return true;

if (board[1][0] == board[1][1] &&
board[1][1] == board[1][2])
return true;

if (board[0][0] == board[1][1] &&
board[1][1] == board[2][2])
return true;

if (board[0][2] == board [1][1] &&
board[1][1] == board[2][0])
return true;
}

return false;
}

list<Move> getMoves() {
list<Move> moveList;

for(int row = 0; row < 3; row++)
for(int col = 0; col < 3; col++)
if (board[row][col] == 0)
moveList.push_back(Move(row, col));

return moveList;
}
};

ostream& operator<< (ostream& stream, Board& board) {
board.print(stream);
return stream;
}

istream& operator>> (istream& stream, Board& board) {
board.read(stream);
return stream;
}

int evaluate(Board& board) {
int score = board.isWon() ? 100 : 0;

for(int row = 0; row < 3; row++)
for(int col = 0; col < 3; col++)
if (board.board[row][col] == 0)
score += 1;

return score;
}

int negamax(Board& board, int depth, int player, int alpha, int beta) {
if (board.isWon() || depth <= 0) {
#if DEBUG > 1
cout << "Found winner board at depth " << depth << endl;
cout << board << endl;
#endif
return player * evaluate(board);
}

list<Move> allMoves = board.getMoves();

if (allMoves.size() == 0)
return player * evaluate(board);

for(list<Move>::iterator it = allMoves.begin(); it != allMoves.end(); it++) {
board.do_move(*it, -player);
int val = -negamax(board, depth - 1, -player, -beta, -alpha);
board.undo_move(*it);

if (val >= beta)
return val;

if (val > alpha)
alpha = val;
}

return alpha;
}

void nextMove(Board& board) {
list<Move> allMoves = board.getMoves();
Move* bestMove = NULL;
int bestScore = INT_MIN;

for(list<Move>::iterator it = allMoves.begin(); it != allMoves.end(); it++) {
board.do_move(*it, 1);
int score = -negamax(board, 100, 1, INT_MIN + 1, INT_MAX);
board.undo_move(*it);

#if DEBUG
cout << it->row << ' ' << it->col << " = " << score << endl;
#endif

if (score > bestScore) {
bestMove = &*it;
bestScore = score;
}
}

if (!bestMove)
return;

cout << bestMove->row << ' ' << bestMove->col << endl;

#if DEBUG
board.do_move(*bestMove, 1);
cout << board;
#endif

}

int main() {
Board board;

cin >> board;
#if DEBUG
cout << "Starting board:" << endl;
cout << board;
#endif

nextMove(board);
return 0;
}

给出这个输入:

O
X__
___
___

算法选择在 0、1 处下棋子,造成一定的损失,对这个陷阱做(没有什么可以赢或以平局结束):

XO_
X__
___

我很确定游戏实现是正确的,但算法也应该是正确的。

编辑:更新了evaluatenextMove

EDIT2: 修复了第一个问题,但似乎仍然存在错误

最佳答案

您的evaluate 函数会计算空白,但不会识别获胜的棋盘。

编辑:
nextMove 中还有一个相对较小的问题。该行应该是

int score = -negamax(board, 0, -1, INT_MIN + 1, INT_MAX);

修复该问题(并评估),然后代码选择正确的着法。

编辑:

这修复了它:

if (board.isWon() || depth <= 0) {
#if DEBUG > 1
cout << "Found winner board at depth " << depth << endl;
cout << board << endl;
#endif
return -100;
}

这些问题几乎都源于没有搞清楚score的含义。它是从播放器的角度来看的。如果 negamax 正在评估玩家 1 的位置,而玩家 1 无法获胜,则分数应该很低(例如 -100);如果 negamax 正在评估玩家 -1 的位置,而玩家 -1 无法获胜,则分数应该较低(例如 -100)。如果 evaluate() 无法区分玩家,那么返回 player * evaluate(board) 的分数就是错误的。

关于c++ - Negamax 实现似乎不适用于井字游戏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12428932/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com