我写了一个极大极小算法与α+β修剪为游戏跳棋,现在我想使用重写它negamax方法。我期望两者是相等的,因为negamax只是一种写minimax的技术。但是由于某种原因,我的两种算法的行为有所不同。当我在相同的输入上运行它们时,negamax版本似乎可以评估更多状态,因此我认为alpha beta修剪一定有问题。
下面的代码同时显示了算法(minimax和negamax函数),并在底部显示了play我从中调用它们的函数。该evaluate函数是我用来评估两种算法中状态的基本启发式方法。
minimax
negamax
play
evaluate
发现错误的任何帮助将不胜枚举。
#include "player.hpp" #include <algorithm> #include <limits> #include <cstdlib> namespace checkers { int evaluatedStates = 0; int evaluate(const GameState &state) { // FIXME: Improve heuristics. int redScore = 0; int whiteScore = 0; int piece = 0; for (int i = 1; i <= 32; ++i) { piece = state.at(i); if (piece & CELL_RED) { ++redScore; if (piece & CELL_KING) redScore += 2; // King bonus. } else if (piece & CELL_WHITE) { ++whiteScore; if (piece & CELL_KING) whiteScore += 2; // King bonus. } } return state.getNextPlayer() == CELL_RED ? whiteScore - redScore : redScore - whiteScore; } int minimax(const GameState &state, int depth, int a, int b, bool max) { if (depth == 0 || state.isEOG()) { ++evaluatedStates; return evaluate(state); } std::vector<GameState> possibleMoves; state.findPossibleMoves(possibleMoves); if (max) { for (const GameState &move : possibleMoves) { a = std::max(a, minimax(move, depth - 1, a, b, false)); if (b <= a) return b; // β cutoff. } return a; } else { for (const GameState &move : possibleMoves) { b = std::min(b, minimax(move, depth - 1, a, b, true)); if (b <= a) return a; // α cutoff. } return b; } } int negamax(const GameState &state, int depth, int a, int b) { if (depth == 0 || state.isEOG()) { ++evaluatedStates; return evaluate(state); } std::vector<GameState> possibleMoves; state.findPossibleMoves(possibleMoves); for (const GameState &move : possibleMoves) { a = std::max(a, -negamax(move, depth - 1, -b, -a)); if (b <= a) return b; // β cutoff. } return a; } GameState Player::play(const GameState &pState, const Deadline &pDue) { GameState bestMove(pState, Move()); std::vector<GameState> possibleMoves; pState.findPossibleMoves(possibleMoves); int a = -std::numeric_limits<int>::max(); int b = std::numeric_limits<int>::max(); for (const GameState &move : possibleMoves) { int v = negamax(move, 10, a, b); //int v = minimax(move, 10, a, b, false); if (v > a) { a = v; bestMove = move; } } std::cerr << "Evaluated states: " << evaluatedStates << std::endl; return bestMove; } /*namespace checkers*/ }
您的minimax()和negamax()功能正确。我认为那state.getNextPlayer()将返回下一个要移动的玩家。这意味着您evaluate()和negamax()函数从该玩家的角度返回分数。
minimax()
negamax()
state.getNextPlayer()
evaluate()
但是,minimax()从的角度返回分数max。所以,如果你尝试在取消minimax()在你的play()功能,这将导致一个错误
max
play()
//int v = negamax(move, 10, a, b); int v = minimax(move, 10, a, b, false); // assumes perspective of min player ^^^^^ if (v > a) { // assumes perspective of max player a = v; bestMove = move; }
minimax()用true参数替换对的调用应该可以解决该问题:
true
int v = minimax(move, 10, a, b, true); // assumes perspective of max player