1
- use std:: collections:: HashMap ;
1
+ use std:: { collections:: HashMap , cmp } ;
2
2
use tokio:: time:: { Duration , Instant } ;
3
+ use rustc_hash:: FxHasher ;
3
4
4
5
use chess:: { Action , Board , BoardStatus , ChessMove , Color , MoveGen , Piece , BitBoard } ;
5
6
@@ -15,6 +16,7 @@ pub(crate) struct Algorithm {
15
16
pub ( crate ) time_per_move : Duration ,
16
17
/// Number of times that a given board has been played
17
18
pub ( crate ) board_played_times : HashMap < Board , u32 > ,
19
+ pub ( crate ) pawn_hash : HashMap < BitBoard , f32 >
18
20
}
19
21
20
22
impl Algorithm {
@@ -24,6 +26,7 @@ impl Algorithm {
24
26
transposition_table : HashMap :: with_capacity ( 45 ) ,
25
27
time_per_move,
26
28
board_played_times : HashMap :: new ( ) ,
29
+ pawn_hash : HashMap :: new ( )
27
30
}
28
31
}
29
32
@@ -40,6 +43,8 @@ impl Algorithm {
40
43
num_extensions : u32 ,
41
44
board_played_times_prediction : & mut HashMap < Board , u32 > ,
42
45
) -> Evaluation {
46
+
47
+
43
48
if depth == 0 {
44
49
stats. leaves_visited += 1 ;
45
50
let eval = self . eval ( board, board_played_times_prediction) ;
@@ -67,14 +72,17 @@ impl Algorithm {
67
72
68
73
// If we arrive at here and it is checkmate, then we know that the side playing
69
74
// has been checkmated.
70
-
75
+
71
76
best_evaluation. eval = Some ( if board. side_to_move ( ) == Color :: White {
72
77
f32:: MIN
73
78
} else {
74
79
f32:: MAX
75
80
} ) ;
76
81
return best_evaluation;
77
- }
82
+ }
83
+
84
+ //best_evaluation.eval = Some(f32::MIN);
85
+
78
86
79
87
let mut boards = legal_moves
80
88
. map ( |chess_move| {
@@ -114,6 +122,11 @@ impl Algorithm {
114
122
( i. saturating_sub ( 1 ) ) as f32 / num_legal_moves as f32 ;
115
123
return best_evaluation;
116
124
} ;
125
+
126
+ if depth > stats. max_depth {
127
+ stats. max_depth = depth;
128
+ }
129
+
117
130
if module_enabled ( self . modules , SKIP_BAD_MOVES )
118
131
&& i as f32 > num_legal_moves as f32 * 1.
119
132
{
@@ -159,6 +172,7 @@ impl Algorithm {
159
172
) ;
160
173
evaluation
161
174
} ;
175
+
162
176
stats. nodes_visited += 1 ;
163
177
164
178
// Replace best_eval if ours is better
@@ -309,7 +323,7 @@ impl Algorithm {
309
323
}
310
324
311
325
pub ( crate ) fn eval (
312
- & self ,
326
+ & mut self ,
313
327
board : & Board ,
314
328
board_played_times_prediction : & HashMap < Board , u32 > ,
315
329
) -> f32 {
@@ -351,10 +365,9 @@ impl Algorithm {
351
365
//Essentially, gets the dot product between a "vector" of the bitboard (containing 64 0s and 1s) and the table with position bonus constants.
352
366
let mut bonus: f32 = 0. ;
353
367
//Get's the bitboard with all piece positions, and runs bitwise and for the board having one's own colors.
354
- let mut piece_board: u64 = ( piece_bitboard & color_bitboard) . reverse_colors ( ) . to_size ( 0 ) as u64 ;
355
368
for i in 0 ..63 {
356
- //I'm pretty sure the bitboard and position_table have opposite orientationns. Regardless, flipping the bitboard significantly increased performance .
357
- bonus += ( piece_board >> i & 1 ) as f32 * position_table[ i] ;
369
+ //The position table and bitboard are flipped vertically, hence .reverse_colors(). Reverse colors is for some reason faster than replacing i with 56-i+2*(i%8) .
370
+ bonus += ( ( piece_bitboard & color_bitboard ) . reverse_colors ( ) . to_size ( 0 ) >> i & 1 ) as f32 * position_table[ i] ;
358
371
}
359
372
return bonus;
360
373
}
@@ -375,12 +388,54 @@ impl Algorithm {
375
388
}
376
389
}
377
390
378
- let evaluation: f32 = controlled_squares as f32 / 20. + diff_material as f32 + position_bonus;
391
+ let mut pawn_structure: f32 = 0. ;
392
+ if utils:: module_enabled ( self . modules , modules:: PAWN_STRUCTURE ) {
393
+ fn pawn_structure_calc ( all_pawn_bitboard : & BitBoard , color_bitboard : & BitBoard , all_king_bitboard : & BitBoard ) -> f32 {
394
+ let mut bonus: f32 = 0. ;
395
+ let pawn_bitboard: usize = ( all_pawn_bitboard & color_bitboard) . to_size ( 0 ) ;
396
+ let king_bitboard: usize = ( all_king_bitboard & color_bitboard) . to_size ( 0 ) ;
397
+ //pawn chain, awarding 0.5 eval for each pawn protected by another pawn.
398
+ bonus += 0.5 * ( ( pawn_bitboard & ( pawn_bitboard << 7 ) ) . count_ones ( ) + ( pawn_bitboard & ( pawn_bitboard << 9 ) ) . count_ones ( ) ) as f32 ;
399
+
400
+ //stacked pawns. -0.5 points per rank containing >1 pawns. By taking the pawn bitboard and operating bitwise and for another bitboard (integer) where the leftmost rank is filled. This returns
401
+ for i in 0 ..7 {
402
+ //constant 9259542123273814144 = 0x8080808080808080, or the entire first rank.
403
+ bonus -= 0.5 * cmp:: max ( ( pawn_bitboard & ( 0x8080808080808080 >> i) ) . count_ones ( ) as i64 - 1 , 0 ) as f32 ;
404
+ }
405
+
406
+ //king safety. Outer 3 pawns get +1 eval bonus per pawn if king is behind them. King position required is either ..X..... or ......X.
407
+ if ( king_bitboard & 0x2 ) . count_ones ( ) > 0 {
408
+ bonus += ( pawn_bitboard & 0x7 ) . count_ones ( ) as f32 ;
409
+ }
410
+ if ( king_bitboard & 0x20 ) . count_ones ( ) > 0 {
411
+ bonus += ( pawn_bitboard & 0xE000 ) . count_ones ( ) as f32 ;
412
+ }
413
+ return bonus;
414
+ }
415
+
416
+ //Because pawn moves (according to chessprogramming.org) are rarely performed, hashing them is useful.
417
+ if board. side_to_move ( ) == Color :: White {
418
+ let pawn_bitboard: BitBoard = board. pieces ( Piece :: Pawn ) & board. color_combined ( Color :: White ) ;
419
+ if !self . pawn_hash . contains_key ( & pawn_bitboard) {
420
+ self . pawn_hash . insert ( pawn_bitboard, pawn_structure_calc ( board. pieces ( Piece :: Pawn ) , board. color_combined ( Color :: White ) , board. pieces ( Piece :: King ) ) ) ;
421
+ }
422
+ pawn_structure = * self . pawn_hash . get ( & pawn_bitboard) . unwrap ( ) ;
423
+ } else {
424
+ let pawn_bitboard: BitBoard = board. pieces ( Piece :: Pawn ) & board. color_combined ( Color :: Black ) ;
425
+ if !self . pawn_hash . contains_key ( & pawn_bitboard) {
426
+ self . pawn_hash . insert ( pawn_bitboard, pawn_structure_calc ( board. pieces ( Piece :: Pawn ) , board. color_combined ( Color :: Black ) , board. pieces ( Piece :: King ) ) ) ;
427
+ }
428
+ pawn_structure = * self . pawn_hash . get ( & pawn_bitboard) . unwrap ( ) ;
429
+ }
430
+ }
431
+
432
+ let evaluation: f32 = controlled_squares as f32 / 20. + diff_material as f32 + position_bonus + pawn_structure;
379
433
return evaluation
380
434
}
381
435
382
436
pub ( crate ) fn reset ( & mut self ) {
383
437
self . transposition_table = HashMap :: new ( ) ;
384
438
self . board_played_times = HashMap :: new ( ) ;
439
+ self . pawn_hash = HashMap :: new ( ) ;
385
440
}
386
441
}
0 commit comments