I’m writing a Othello engine using minimax with alpha-beta pruning.
It’s working ok, but i found the following problem:
When the algorithm finds that a position is lost, it returns -INFINITY as expected, but in
this case i’m not able to track the ‘best’ move…the position is already lost, but it should return a valid move anyway (preferably a move that survives longer, as the good chess engines does).
Here is the code:
private float minimax(OthelloBoard board, OthelloMove best, float alpha, float beta, int depth)
{
OthelloMove garbage = new OthelloMove();
int currentPlayer = board.getCurrentPlayer();
if (board.checkEnd())
{
int bd = board.countDiscs(OthelloBoard.BLACK);
int wd = board.countDiscs(OthelloBoard.WHITE);
if ((bd > wd) && currentPlayer == OthelloBoard.BLACK)
return INFINITY;
else if ((bd < wd) && currentPlayer == OthelloBoard.BLACK)
return -INFINITY;
else if ((bd > wd) && currentPlayer == OthelloBoard.WHITE)
return -INFINITY;
else if ((bd < wd) && currentPlayer == OthelloBoard.WHITE)
return INFINITY;
else
return 0.0f;
}
//search until the end? (true during end game phase)
if (!solveTillEnd )
{
if (depth == maxDepth)
return OthelloHeuristics.eval(currentPlayer, board);
}
ArrayList<OthelloMove> moves = board.getAllMoves(currentPlayer);
for (OthelloMove mv : moves)
{
board.makeMove(mv);
float score = - minimax(board, garbage, -beta, -alpha, depth + 1);
board.undoMove(mv);
if(score > alpha)
{
//Set Best move here
alpha = score;
best.setFlipSquares(mv.getFlipSquares());
best.setIdx(mv.getIdx());
best.setPlayer(mv.getPlayer());
}
if (alpha >= beta)
break;
}
return alpha;
}
I call it using:
AI ai = new AI(board, maxDepth, solveTillEnd);
//create empty (invalid) move to hold best move
OthelloMove bestMove = new OthelloMove();
ai.bestFound = bestMove;
ai.minimax(board, bestMove, -INFINITY, INFINITY, 0);
//dipatch a Thread
new Thread(ai).start();
//wait for thread to finish
OthelloMove best = ai.bestFound();
When a lost position (imagine it’s lost 10 moves later for example) is searched, best variable above is equal to the empty invalid move passed as argument…why??
Thanks for any help!
Your problem is that you’re using -INFINITY and +INFINITY as win/loss scores. You should have scores for win/loss that are higher/lower than any other positional evaluation score, but not equal to your infinity values. This will guarantee that a move will be chosen even in positions that are hopelessly lost.