Skip to content

Commit

Permalink
Improve game phase calculation for tapered eval
Browse files Browse the repository at this point in the history
  • Loading branch information
mhonert committed Jul 19, 2020
1 parent b91ac03 commit 46e5eb4
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 49 deletions.
15 changes: 13 additions & 2 deletions assembly/__tests__/board.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,14 +485,25 @@ describe('Evaluate position', () => {
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, P, 0, 0, 0, 0,
0, P, 0, 0, 0, 0, 0, 0,
0, 0, 0, P, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, +K, 0, 0, 0, 0,
0, 0, 0
]);

expect(board.getScore()).toBeLessThan(board.getMaterialScore());
const doubledPawnBoard = new Board([
0, 0, 0, -K, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, P, 0, 0, 0, 0,
0, 0, 0, P, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, +K, 0, 0, 0, 0,
0, 0, 0
]);
expect(doubledPawnBoard.getScore()).toBeLessThan(board.getScore());
});

it('Calculates lower score for doubled pawns on all squares', () => {
Expand Down
52 changes: 19 additions & 33 deletions assembly/board.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,13 @@ const BISHOP_MOB_BONUS: i32 = 5;
const ROOK_MOB_BONUS: i32 = 5;
const QUEEN_MOB_BONUS: i32 = 5;


const BASE_PIECE_PHASE_VALUE: i32 = 2;
const PAWN_PHASE_VALUE: i32 = -1; // relative to the base piece value
const QUEEN_PHASE_VALUE: i32 = 4; // relative to the base piece value

const MAX_PHASE: i32 = 16 * PAWN_PHASE_VALUE + 30 * BASE_PIECE_PHASE_VALUE + 2 * QUEEN_PHASE_VALUE;

export class Board {
private items: StaticArray<i32>;
private whiteKingIndex: i32;
Expand All @@ -117,8 +124,6 @@ export class Board {

private positionHistory: PositionHistory = new PositionHistory();

private endgame: i32;

/* items Array:
Index 0 - 63: Board representation (8 columns * 8 rows)
Index 64: Half-move clock (number of halfmoves since last capture or pawn move)
Expand Down Expand Up @@ -152,8 +157,6 @@ export class Board {
unchecked(this.items[STATE_INDEX] = items[STATE_INDEX]);
this.halfMoveClock = i16(items[HALFMOVE_CLOCK_INDEX]);
this.halfMoveCount = i16(items[HALFMOVE_COUNT_INDEX]);

this.updateEndGameStatus();
}

@inline
Expand Down Expand Up @@ -220,7 +223,7 @@ export class Board {

@inline
getMaterialScore(): i32 {
return this.isEndGame() ? this.egScore : this.score;
return this.score;
}

@inline
Expand Down Expand Up @@ -263,15 +266,22 @@ export class Board {
}
}

const whitePieces = this.getAllPieceBitBoard(WHITE);
const blackPieces = this.getAllPieceBitBoard(BLACK);

// Interpolate between opening/mid-game score and end game score for a smooth eval score transition
const pawnCount: i32 = i32(popcnt(whitePawns | blackPawns));
const piecesExceptKingCount: i32 = i32(popcnt((whitePieces | blackPieces))) - 2; // -2 for two kings

const whiteQueens = this.getBitBoard(QUEEN);
const blackQueens = this.getBitBoard(-QUEEN);

const queenPhaseScore: i32 = (whiteQueens > 0 ? QUEEN_PHASE_VALUE : 0) + (blackQueens > 0 ? QUEEN_PHASE_VALUE : 0);

// Interpolate between opening/mid-game score and the end game score for a smooth transition
const phase: i32 = i32(popcnt(whitePawns | blackPawns)) + (whiteQueens > 0 ? 1 : 0) * 4 + (blackQueens > 0 ? 1 : 0) * 4;
const egPhase: i32 = 24 - phase;
const phase: i32 = pawnCount * PAWN_PHASE_VALUE + piecesExceptKingCount * BASE_PIECE_PHASE_VALUE + queenPhaseScore;
const egPhase: i32 = MAX_PHASE - phase;

let interpolatedScore = ((score * phase) + (egScore * egPhase)) / 24;
let interpolatedScore = ((score * phase) + (egScore * egPhase)) / MAX_PHASE;

// Perform evaluations which apply to all game phases

Expand All @@ -290,9 +300,6 @@ export class Board {
interpolatedScore -= this.calcDoubledPawnPenalty(whitePawns);
interpolatedScore += this.calcDoubledPawnPenalty(blackPawns);

const whitePieces = this.getAllPieceBitBoard(WHITE);
const blackPieces = this.getAllPieceBitBoard(BLACK);

interpolatedScore += this.mobilityScore(whitePawnAttacks, blackPawnAttacks, whitePieces, blackPieces);


Expand Down Expand Up @@ -1215,27 +1222,6 @@ export class Board {
}
}

@inline
isEndGame(): bool {
return this.endgame != 0;
}

@inline
updateEndGameStatus(): void {
const pawnCount = popcnt(this.getBitBoard(PAWN)) + popcnt(this.getBitBoard(-PAWN));
if (pawnCount <= 3) {
this.endgame = 1;
return;
}
const otherPieceCount = popcnt(this.getBitBoard(KNIGHT)) + popcnt(this.getBitBoard(-KNIGHT)) +
popcnt(this.getBitBoard(BISHOP)) + popcnt(this.getBitBoard(-BISHOP)) +
popcnt(this.getBitBoard(ROOK)) + popcnt(this.getBitBoard(-ROOK)) +
popcnt(this.getBitBoard(QUEEN)) + popcnt(this.getBitBoard(-QUEEN));

this.endgame = otherPieceCount <= 3 ? 1 : 0;
}


@inline
isPawnMoveCloseToPromotion(piece: i32, moveEnd: i32, movesLeft: i32): bool {
if (piece == PAWN) {
Expand Down
6 changes: 0 additions & 6 deletions assembly/engine.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ export class Engine {
private startTime: i64 = 0;
private nodeCount: u64 = 0;
private timeLimitMillis: i64;
private isEndGame: bool = false;
private isCancelPossible: bool = false;
private useOpeningBook: bool = false;
private openingBookPlyLimit: i32 = getOpeningBookPlyLimit();
Expand Down Expand Up @@ -115,8 +114,6 @@ export class Engine {
this.history.clear();

this.board.setHistory(this.history);

this.isEndGame = board.isEndGame();
}

setUseOpeningBook(use: bool): void {
Expand All @@ -131,7 +128,6 @@ export class Engine {
if (this.board.getHalfMoveClock() == 0) {
this.history.clear();
}
this.isEndGame = this.board.isEndGame();
}

// Find the best possible move in response to the current board position.
Expand Down Expand Up @@ -842,13 +838,11 @@ class EngineControl {

setBoard(board: Board): void {
this.board = board;
this.board.updateEndGameStatus();
this.engine.setBoard(board);
}

performMove(move: i32, increaseTTableAge: bool = true): void {
this.board.performEncodedMove(move);
this.board.updateEndGameStatus();
this.engine.refreshStateAfterMove(increaseTTableAge);
}

Expand Down
15 changes: 7 additions & 8 deletions assembly/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,14 @@ import { BLACK, calculatePieceSquareTables, WHITE } from './board';
import { randomizeOpeningBookMoves } from './opening-book';
import { stdio } from './io';
import { VERSION } from '../version';
import { resetPieceValues } from './pieces';

const DIFFICULTY_LEVELS: Array<Array<i32>> = [
[1, 0, 0],
[3, 0, 0],
[5, 0, 0],
[7, 0, 0],
[9, 0, 0],
[11, 1000, 1500]
[1, 0],
[3, 0],
[5, 0],
[7, 0],
[9, 0],
[11, 1250]
]

export const INT32ARRAY_ID = idof<Int32Array>();
Expand Down Expand Up @@ -81,7 +80,7 @@ export function setPosition(fen: string, moves: Int32Array): Int32Array {
export function calculateMove(difficultyLevel: i32): i32 {
const levelSettings = DIFFICULTY_LEVELS[difficultyLevel - 1];

const maxTime = EngineControl.getBoard().isEndGame() ? levelSettings[2] : levelSettings[1];
const maxTime = levelSettings[1];
const minimumSearchDepth = levelSettings[0];

return EngineControl.findBestMove(minimumSearchDepth, maxTime, maxTime === 0);
Expand Down

0 comments on commit 46e5eb4

Please sign in to comment.