@@ -19,9 +19,13 @@ 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- // Slight mobility bonus
23- const moves = allLegalMoves ( state ) . length ;
24- s += ( state . turn === color ? moves : - moves ) * 2 ;
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.
24+ const boardArea = boardWidth ( state ) * boardHeight ( state ) ;
25+ if ( boardArea <= 100 ) {
26+ const moves = allLegalMoves ( state ) . length ;
27+ s += ( state . turn === color ? moves : - moves ) * 2 ;
28+ }
2529 return s ;
2630}
2731
@@ -115,7 +119,9 @@ export async function chooseBotMove(state: GameState, level: number, opts?: BotO
115119 // Level 6+: deterministic minimax fallback if external engine is unavailable.
116120 const blunderChanceByLevel : Record < number , number > = { 1 : 0.8 , 2 : 0.5 , 3 : 0.15 , 4 : 0.03 } ;
117121 const blunderChance = blunderChanceByLevel [ normalizedLevel ] ?? 0 ;
118- const depth = normalizedLevel <= 2 ? 1 : normalizedLevel <= 4 ? 2 : normalizedLevel <= 8 ? 3 : 4 ;
122+ const boardArea = boardWidth ( state ) * boardHeight ( state ) ;
123+ const depthCap = boardArea > 200 ? 1 : boardArea > 100 ? 2 : 4 ;
124+ const depth = Math . min ( depthCap , normalizedLevel <= 2 ? 1 : normalizedLevel <= 4 ? 2 : normalizedLevel <= 8 ? 3 : 4 ) ;
119125
120126 if ( rng ( ) < blunderChance ) {
121127 const captures = moves . filter ( ( m ) => m . captured ) ;
0 commit comments