I have a problem with minimax. Notice that in the isFinished and evaluateBoard methods I distinguish which player won.
However, when the condition is met in minimax:
if(game.isFinished() || depth == 0)
{
return game.evaluateBoard(playerColor);
}
Is the evaluateBoard method always evaluated from the point of view of the losing player.
I’m not sure if I’m explaining this correctly, but for example if I want to maximize the white player’s move, then in the penultimate dive I call int eval = minimaxAlphaBetaAlg(gameCopy, depth - 1, alpha, beta, false, m_Player, originalDepth, bestFrom, bestTo);
i.e. the terminating condition in the recursion
if(game.isFinished() || depth == 0)
{
return game.evaluateBoard(playerColor);
}
evaluates to m_Player and is therefore always negative
void CGame::minimaxAlphaBeta(int depth, int typeOponent)
{
size_t i = 0;
Color nextMove = Color::WHITE;
while(!isFinished())
{
if(nextMove == m_Player)
{
makeSimpleMove();
}
else
{
CPosition bestFromPosition;
CPosition bestToPosition;
minimaxAlphaBetaAlg(*this, depth, INT_MIN, INT_MAX, true, m_Computer, depth, bestFromPosition, bestToPosition);
makeMove(bestFromPosition, bestToPosition, m_Computer, true);
}
nextMove = (nextMove == Color::WHITE) ? Color::BLACK : Color::WHITE;
}
}
minimax alg
int CGame::minimaxAlphaBetaAlg(CGame &game, int depth, int alpha, int beta, bool isMaximizingComputer, Color playerColor, int originalDepth, CPosition &bestFrom, CPosition &bestTo)
{
if(game.isFinished() || depth == 0)
{
return game.evaluateBoard(playerColor);
}
if(isMaximizingComputer)
{
int maxEval = INT_MIN;
auto& playableMoves = (m_Computer == Color::WHITE) ? game.m_WhitePlayable : game.m_BlackPlayable;
for (auto& [from, to] : playableMoves)
{
CGame gameCopy = game;
gameCopy.makeMove(from, to, m_Computer, true);
int eval = minimaxAlphaBetaAlg(gameCopy, depth - 1, alpha, beta, false, m_Player, originalDepth, bestFrom, bestTo);
if (eval > maxEval)
{
maxEval = eval;
if(depth == originalDepth)
{
bestFrom = from;
bestTo = to;
}
}
alpha = max(alpha, maxEval);
if(beta <= alpha)
break;
}
return maxEval;
}
else
{
int minEval = INT_MAX;
auto& playableMoves = (m_Player == Color::WHITE) ? game.m_WhitePlayable : game.m_BlackPlayable;
for (auto &[from, to] : playableMoves)
{
CGame gameCopy = game;
gameCopy.makeMove(from, to, m_Player, true);
int eval = minimaxAlphaBetaAlg(gameCopy, depth - 1, alpha, beta, true, m_Computer, originalDepth, bestFrom, bestTo);
minEval = min(minEval, eval);
beta = min(beta, minEval);
if(beta <= alpha)
break;
}
return minEval;
}
}
Evaluate function
int CGame::evaluateBoard(Color color)
{
int eval = 0;
for(long int i = 0; i < m_Board.getSize(); i++)
{
for (long int j = 0; j < m_Board.getSize(); j++)
{
if(m_Board[i][j].getType() == Type::QUEEN)
{
if(m_Board[i][j].getColor() == color)
eval += 25;
else
eval -= 25;
}
...
}
if(isFinished() == 1)
{
(color == Color::BLACK) ? eval += 80 : eval -= 80;
}
if(isFinished() == 2)
{
(color == Color::WHITE) ? eval += 80 : eval -= 80;
}
return eval;
}
isFinished method
which player won 1) Black 2) White, 3) Draw
int CGame::isFinished()
{
if(m_Board.isPieceUnderAttack(m_WhiteKing, Color::WHITE, m_WhitePlayable, m_BlackPlayable) && m_WhitePlayable.empty())
return 1;
if(m_Board.isPieceUnderAttack(m_BlackKing, Color::BLACK, m_WhitePlayable, m_BlackPlayable) && m_BlackPlayable.empty())
return 2;
if(m_BlackPlayable.empty() || m_WhitePlayable.empty())
return 3;
return 0;
}
Complet code: https://onecompiler.com/cpp/42eaxusbf
user24995323 is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.