1- use chess:: { Board , Piece } ;
1+ use chess:: { Board , Color , File , Piece , Rank , Square } ;
22use crate :: bot:: { include:: types:: GlobalMap , util:: { board:: BoardExt , piece:: piece_value } } ;
33
4- fn is_endgame ( board : & Board ) -> bool {
5- // Simple heuristic: endgame if total material (excluding kings) is low
6- let mut non_king_material = 0 ;
7-
8- for sq in chess:: ALL_SQUARES {
9- if let Some ( piece) = board. piece_on ( sq) {
10- if piece == Piece :: King {
11- continue ;
12- }
13-
14- non_king_material += match piece {
15- Piece :: Pawn => 100 ,
16- Piece :: Knight => 320 ,
17- Piece :: Bishop => 330 ,
18- Piece :: Rook => 500 ,
19- Piece :: Queen => 900 ,
20- _ => 0 ,
21- } ;
22- }
23- }
24-
25- non_king_material < 1600 // adjust threshold as needed
26- }
27-
28- fn square_distance ( a : chess:: Square , b : chess:: Square ) -> u8 {
29- let file_dist = ( ( a. get_file ( ) . to_index ( ) as i32 ) - ( b. get_file ( ) . to_index ( ) as i32 ) ) . abs ( ) ;
30- let rank_dist = ( ( a. get_rank ( ) . to_index ( ) as i32 ) - ( b. get_rank ( ) . to_index ( ) as i32 ) ) . abs ( ) ;
31- ( file_dist + rank_dist) as u8
4+ fn distance_between ( a : Square , b : Square ) -> u8 {
5+ let file_distance = ( ( a. get_file ( ) . to_index ( ) as i8 ) - ( b. get_file ( ) . to_index ( ) as i8 ) ) . abs ( ) ;
6+ let rank_distance = ( ( a. get_rank ( ) . to_index ( ) as i8 ) - ( b. get_rank ( ) . to_index ( ) as i8 ) ) . abs ( ) ;
7+ ( file_distance + rank_distance) as u8
328}
339
34- fn evaluate_king_proximity ( board : & Board ) -> i32 {
35- use chess:: { Color :: * , Piece :: King } ;
36-
37- if !is_endgame ( board) {
38- return 0 ;
10+ fn evaluate_king_proximity ( board : & Board , is_endgame : bool ) -> i32 {
11+ if is_endgame {
12+ let white_king_sq = ( board. pieces ( Piece :: King ) & board. color_combined ( Color :: White ) )
13+ . into_iter ( )
14+ . next ( )
15+ . unwrap ( ) ;
16+ let black_king_sq = ( board. pieces ( Piece :: King ) & board. color_combined ( Color :: Black ) )
17+ . into_iter ( )
18+ . next ( )
19+ . unwrap ( ) ;
20+
21+ let proximity = distance_between ( white_king_sq, black_king_sq) as i32 ;
22+ let score = 11 + ( 14 - proximity) ;
23+
24+ return score;
3925 }
4026
41- let white_king_sq = ( board. pieces ( King ) & board. color_combined ( White ) )
42- . into_iter ( )
43- . next ( )
44- . unwrap ( ) ;
45- let black_king_sq = ( board. pieces ( King ) & board. color_combined ( Black ) )
46- . into_iter ( )
47- . next ( )
48- . unwrap ( ) ;
49-
50- let dist = square_distance ( white_king_sq, black_king_sq) ;
51- let proximity_score = 10 - ( dist as i32 ) ; // Closer = better
52-
53- proximity_score * 3
27+ 0
5428}
5529
5630fn evaluate_connected_pawns ( board : & Board ) -> i32 {
@@ -66,21 +40,84 @@ fn evaluate_connected_pawns(board: &Board) -> i32 {
6640 let file = sq. get_file ( ) . to_index ( ) ;
6741
6842 let connected = [ -1 , 1 ] . iter ( ) . any ( |& df| {
69- let f = ( ( file as isize ) + df) as usize ;
70- if f > 7 {
43+ let f = ( file as isize ) + df;
44+ if f < 0 || f > 7 {
7145 return false ;
7246 }
73- let adj_sq = chess:: Square :: make_square (
74- chess:: Rank :: from_index ( rank) ,
75- chess:: File :: from_index ( f)
76- ) ;
77- board. piece_on ( adj_sq) == Some ( Pawn ) && board. color_on ( adj_sq) == Some ( color)
47+
48+ // Check same rank, one ahead, and one behind
49+ [ -1 , 0 , 1 ] . iter ( ) . any ( |& dr| {
50+ let r = ( rank as isize ) + dr;
51+ if r < 0 || r > 7 {
52+ return false ;
53+ }
54+
55+ let adj_sq = chess:: Square :: make_square (
56+ chess:: Rank :: from_index ( r as usize ) ,
57+ chess:: File :: from_index ( f as usize )
58+ ) ;
59+ board. piece_on ( adj_sq) == Some ( Pawn ) && board. color_on ( adj_sq) == Some ( color)
60+ } )
7861 } ) ;
7962
8063 if connected {
8164 score += match color {
82- White => 10 ,
83- Black => -10 ,
65+ White => 15 ,
66+ Black => -15 ,
67+ } ;
68+ }
69+ }
70+ }
71+
72+ score
73+ }
74+
75+ pub fn evaluate_passed_pawns ( board : & Board ) -> i32 {
76+ use Color :: { White , Black } ;
77+ use Piece :: Pawn ;
78+
79+ let mut score = 0 ;
80+
81+ for & color in & [ White , Black ] {
82+ let pawns = board. pieces ( Pawn ) & board. color_combined ( color) ;
83+ let opponent_color = match color {
84+ Color :: White => Color :: Black ,
85+ Color :: Black => Color :: White ,
86+ } ;
87+
88+ for sq in pawns {
89+ let rank_idx = sq. get_rank ( ) . to_index ( ) ;
90+ let file_idx = sq. get_file ( ) . to_index ( ) ;
91+
92+ // Check files: current, left, right
93+ let file_range = file_idx. saturating_sub ( 1 ) ..=( file_idx + 1 ) . min ( 7 ) ;
94+
95+ let is_passed = file_range. clone ( ) . all ( |f| {
96+ let file = File :: from_index ( f) ;
97+ match color {
98+ White => {
99+ // Check ahead of current rank
100+ ( rank_idx + 1 ..=7 ) . all ( |r| {
101+ let sq = Square :: make_square ( Rank :: from_index ( r) , file) ;
102+ board. piece_on ( sq) != Some ( Pawn ) ||
103+ board. color_on ( sq) != Some ( opponent_color)
104+ } )
105+ }
106+ Black => {
107+ // Check behind current rank
108+ ( 0 ..rank_idx) . all ( |r| {
109+ let sq = Square :: make_square ( Rank :: from_index ( r) , file) ;
110+ board. piece_on ( sq) != Some ( Pawn ) ||
111+ board. color_on ( sq) != Some ( opponent_color)
112+ } )
113+ }
114+ }
115+ } ) ;
116+
117+ if is_passed {
118+ score += match color {
119+ White => 15 ,
120+ Black => -15 ,
84121 } ;
85122 }
86123 }
@@ -93,15 +130,20 @@ pub fn evaluate_board(board: &Board) -> i32 {
93130 use chess:: { Piece :: * , Color :: * } ;
94131
95132 // Fifty-move rule draw
96- if board. halfmove_clock ( ) >= 50 {
133+ if board. halfmove_clock ( ) >= 100 {
97134 return 0 ;
98135 }
99136
100137 // Check for checkmate
101138 if board. status ( ) == chess:: BoardStatus :: Checkmate {
102139 return if board. side_to_move ( ) == White { -10_000 } else { 10_000 } ;
140+ } else if board. status ( ) == chess:: BoardStatus :: Stalemate {
141+ return 0 ;
103142 }
104143
144+ let white_base: i32 = board. material_score ( chess:: Color :: White ) ;
145+ let black_base = board. material_score ( chess:: Color :: Black ) ;
146+
105147 let mut white_total = 0 ;
106148 let mut black_total = 0 ;
107149 let mut white_bishops = 0 ;
@@ -160,9 +202,8 @@ pub fn evaluate_board(board: &Board) -> i32 {
160202 return 0 ;
161203 }
162204
163- // Case 2: One side has only king+bishop or king+knight; ignore its score
164205 let mut score: i32 = 0 ;
165- let is_endgame = is_endgame ( board ) ;
206+ let is_endgame = white_base + black_base < 1600 ;
166207
167208 for sq in chess:: ALL_SQUARES {
168209 if let Some ( piece) = board. piece_on ( sq) {
@@ -189,22 +230,29 @@ pub fn evaluate_board(board: &Board) -> i32 {
189230 }
190231 } ;
191232
192- let value = base + positional;
193-
233+ // Case 2: One side has only king+bishop or king+knight; ignore its base score
194234 if color == White {
195235 if !is_minor_or_lone ( white_total, white_bishops, white_knights) {
196- score += value ;
236+ score += base ;
197237 }
238+ score += positional;
198239 } else {
199240 if !is_minor_or_lone ( black_total, black_bishops, black_knights) {
200- score -= value ;
241+ score -= base ;
201242 }
243+ score -= positional;
202244 }
203245 }
204246 }
205247
248+ let proximity_score = evaluate_king_proximity ( board, is_endgame) ;
206249 score += evaluate_connected_pawns ( board) ;
207- score += evaluate_king_proximity ( board) ;
250+ score += evaluate_passed_pawns ( board) ;
251+ if white_base > black_base {
252+ score += proximity_score;
253+ } else {
254+ score -= proximity_score;
255+ }
208256
209257 score
210258}
0 commit comments