Creating a Chess AI Part 1: Evaluation
- Sam Lench
- 2 days ago
- 3 min read
Computers can't really understand if a chess position is good or bad the same way humans do, it reduces everything into a single number - an evaluation number.
That number is exactly what the engine uses to decide what to search, what to ignore and eventually what move to play.
PeSTO is one of many ways we can help the engine make this number actually mean something useful.
Material is Not Enough
The simplest way to evaluate a position is to just assign values to pieces and add them up, Pawns are 100, Knights are 300 etc. This works, but will lead to a weak chess engine.
The problem is that chess isn't just about what pieces exist, where they are is also important.
A knight on the corner of the board is a lot weaker than a knight in the center of the board.
PeSTO
To fix this problem without making the evaluation function overly complicated, we use PeSTO - Piece Square Tables Only.
Instead of separating material and position, we combine everything into simple lookup tables. This keeps everything efficient and effective.
Piece Square Tables (PSTs)
A piece square table is a 64-element array, one value for each square on the chess board. Each value in the array tells us how good or bad it is for a piece to be on that square.
Instead of saying a knight is worth 300, we can say a knight on d4 is worth more than a knight on a1.
Each piece has its own table, and we mirror them for black since they move in the opposite direction.
Stronger engines will have multiple tables for the king because its role changes from being hidden in the early game, to active in the endgame.
The Phases of Chess
PeSTO uses two sets of piece square tables.
Midgame (MG): focuses on king safety, piece activity and center control.
Endgame (EG): Focuses on pawn promotion and king activity.
Instead of switching between them suddenly, we blend between them smoothly as the game transitions from the earlygame to the endgame.
This stops the harsh transitions and naturally shifts the playing style as the game goes on.

Pre-calculating scores
Instead of calculating the material value at runtime, we add the values to the piece square tables, hence the "only" part of piece square tables only. The evaluation then simply becomes a bunch of fast lookups.
Mirroring for black
We don't need to actually store separate tables for black and white, instead we only store whites tables and mirror the board using a cool XOR trick.
squareIndex ^ 56This flips the board vertically, allowing black reuse the same tables as white.
The Evaluation Loop
The evaluation function iterates over all pieces using bitboards, getting midgame and endgame scores separately for both sides.
A simple game phase value is also calculated to control interpolation between the two stages.
public int Evaluate(Bitboards bitboard)
{
int mgWhite = 0, mgBlack = 0, egWhite = 0, egBlack = 0;
int gamePhase = 0;
ulong allPieces = bitboard.GetAllPieces();
while (allPieces != 0)
{
int square = BitboardHelpers.PopLeastSignificantBit(ref allPieces);
int pieceIndex = (int)bitboard.GetPieceOnSquare(square);
if (pieceIndex < 6)
{
mgWhite += _mgTable[pieceIndex][square];
egWhite += _egTable[pieceIndex][square];
}
else
{
mgBlack += _mgTable[pieceIndex][square];
egBlack += _egTable[pieceIndex][square];
}
gamePhase += phaseInc[pieceIndex];
}
int sideToMove = bitboard.GetTurn() ? WHITE : BLACK;
int mgScore = (sideToMove == WHITE) ? (mgWhite - mgBlack) : (mgBlack - mgWhite);
int egScore = (sideToMove == WHITE) ? (egWhite - egBlack) : (egBlack - egWhite);
int mgPhase = Math.Min(gamePhase, 24);
return (mgScore * mgPhase + egScore * (24 - mgPhase)) / 24;
}Why PeSTO?
The big win with PeSTO is efficiency.
There is not much calculation needed during search, just table lookups. That means engines can evaluate positions very fast, allowing it to search more positions per second.
Conclusion
Evaluation is one of the most important parts of a chess engine. It's what tells the engine what is a good or bad move.
By using PeSTO we give our engine the ability to transition how it plays as the game transitions while staying efficient.
It also naturally changes its play style as the game goes on, without needing any complex logic.
