Skip to content

Commit 8295e77

Browse files
committed
Large board move perf: fast eval path skips allLegalMoves on boards > 8x8
1 parent 800a1e9 commit 8295e77

2 files changed

Lines changed: 30 additions & 2 deletions

File tree

src/engine/bot.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ function materialScore(state: GameState, color: "w" | "b"): number {
1919
const v = p.type === "X1" ? customPieceValueForDef(state, p) : (VALUES[p.type] ?? 0);
2020
s += (p.color === color ? 1 : -1) * v;
2121
}
22-
// Mobility bonus: reward having more legal moves than the opponent.
23-
// Only compute this at the leaf level; skip for large boards to keep it fast.
22+
// Mobility bonus: only for small boards where the extra allLegalMoves call is affordable
2423
const boardArea = boardWidth(state) * boardHeight(state);
2524
if (boardArea <= 100) {
2625
const moves = allLegalMoves(state).length;

src/engine/performance.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,29 @@ function evaluatePosition(state: GameState, color: Color): number {
155155
return score;
156156
}
157157

158+
/**
159+
* Cheap position score for large boards: no allLegalMoves calls.
160+
* Computes material directly (avoiding materialScore's mobility allLegalMoves),
161+
* skips gameResult check and reply lookahead.
162+
*/
163+
function fastEvaluatePosition(state: GameState, color: Color): number {
164+
// Material count without mobility bonus (avoids allLegalMoves)
165+
let score = 0;
166+
for (const row of state.board) for (const piece of row) {
167+
if (!piece) continue;
168+
const v = PIECE_DANGER_VALUES[piece.type] ?? 150;
169+
score += (piece.color === color ? 1 : -1) * v;
170+
}
171+
score += pieceDevelopmentBonus(state, color);
172+
score += centerControlBonus(state, color);
173+
score -= hangingPiecePenalty(state, color);
174+
if (inCheck(state, opposite(color))) score += 40;
175+
if (inCheck(state, color)) score -= 55;
176+
const lastMove = state.history[state.history.length - 1];
177+
if (lastMove?.promotion) score += 120;
178+
return score;
179+
}
180+
158181
function gradeFromLoss(loss: number): MoveGrade {
159182
if (loss <= 2) return 5;
160183
if (loss <= 6) return 4;
@@ -285,6 +308,12 @@ function exchangeCredit(state: GameState, move: Move): number {
285308
}
286309

287310
function evaluateMoveLine(next: GameState, color: Color): number {
311+
// Fast path for non-standard boards: skip gameResult (allLegalMoves) and
312+
// reply lookahead — both are O(moves) which explodes on large boards.
313+
if (boardWidth(next) * boardHeight(next) > 64) {
314+
return fastEvaluatePosition(next, color);
315+
}
316+
288317
const immediate = evaluatePosition(next, color);
289318
const result = gameResult(next);
290319
if (result.kind !== "ongoing") return immediate;

0 commit comments

Comments
 (0)