I am working on an AI for Gomoku (5 in a row) but has some issues with the AI not stopping me when I am winning. It just seems to play random moves.
The negamax is basically taken from a connect 4 game I did where the AI seemed to be playing good and stopping me from winning. Here is my code for the AI Negamax function:
private int bestMove;
public int GetBestMove(Gamestate _gamestate, int _maxDepth)
{
// Run negamax function
int originalAlpha = -1000000000;
int originalBeta = 1000000000;
int score = Negamax(_gamestate, _maxDepth, originalAlpha, originalBeta, _gamestate.playerToMove);
return bestMove;
}
public int Negamax(Gamestate _gamestate, int depth, int alpha, int beta, int currentPlayer)
{
// Check for terminal node
int winningPlayer = _gamestate.GetWinner();
if (depth == 0 || winningPlayer != -1 || _gamestate.movesMade == _gamestate.size)
{
if (winningPlayer != -1)
{
if (currentPlayer == winningPlayer)
{
return 10000000;
}
else
{
return -10000000;
}
}
else if (_gamestate.movesMade == _gamestate.size)
{
return 0;
}
else
{
return 0; // Just to test the basic win/loss finding
//return evaluator.EvaluatePosition(_gamestate);
}
}
// Initialize score and bestMove and loop through all possible moves
int score = int.MinValue;
List<int> possibleMoves = _gamestate.possibleMoves;
bestMove = possibleMoves[0];
for (int i = 0; i < possibleMoves.Count; i++)
{
int move = possibleMoves[i];
// Make the move, score it, and then unmake the move again
_gamestate.MakeMove(move);
int newScore = -Negamax(_gamestate, depth - 1, -beta, -alpha, 1 - currentPlayer);
_gamestate.UnmakeMove(move);
if (newScore > score)
{
score = newScore;
bestMove = move;
}
alpha = Mathf.Max(alpha, score);
if (alpha >= beta)
{
break;
}
}
return score;
}
** What is wrong **
- To debug I am playing on a 5x5 board. When I have 4 in a row the AI doesn't play to stop me.
- The AI seems to play random moves, even if my evalutaion at none terminal nodes just returns 0 for now.
What I have tried
- I have checked that my GetWinner() function is correct and returns the player that is winning (0 for first player and 1 for the other player)
- My move generation is simply that I remove the latest played square from a list of all squares when I make a move. And add it again when I unmake a move. So that currently seems to be working fine.
Evaluation Function: Make sure it checks not just for a win or loss, but also for the number of 'open-ended' rows of 2, 3, or 4 stones that each player has. This can give your AI the foresight to block your winning moves. Priority Moves: Your AI should prioritize moves that prevent the opponent from winning on the next turn. So, if there’s a spot that completes a row of 4 for you, the AI should see that as a big red flag and move there first. Depth of Search: Sometimes, the AI needs to look a few moves ahead. Ensure that your _maxDepth parameter is sufficient for the AI to project potential wins or losses a few moves down the line. Debugging: Step through the Negamax function with a debugger when you've got four in a row. Watch the scores it generates for moves—there might be a clue there. Remember, the key to a strong AI is in the details of the evaluation. It’s not about the random moves; it’s about the smart ones!
If this advice helps your AI get its game face on, please consider it a win and accept it.
Best of luck, Ali Shahzad