c4_e5_chess/eval/
simple.rs

1use super::{constants::*, evaluation::Evaluation, helpers::*};
2use crate::misc::types::*;
3use cozy_chess::{Board, Color, Piece};
4
5#[derive(Default)]
6pub struct Simple {}
7
8impl Evaluation for Simple {
9    /// A simple static evaluation function for the given board position.
10    /// It's purpose is, to serve as a baseline for more sophisticated evaluation functions.
11    fn evaluate(b: &Board) -> MoveScore {
12        let mut value: MoveScore = 0;
13        let pieces_count = b.occupied().len();
14
15        let b_open_files = open_files(b);
16        let b_half_open_files = half_open_files(b);
17
18        let (color_attack, color_defend, rank1, rank2, rank3, rank6, rank7, rank8) =
19            if b.side_to_move() == Color::White {
20                (
21                    Color::White,
22                    Color::Black,
23                    CB_RANK_1,
24                    CB_RANK_2,
25                    CB_RANK_3,
26                    CB_RANK_6,
27                    CB_RANK_7,
28                    CB_RANK_8,
29                )
30            } else {
31                (
32                    Color::Black,
33                    Color::White,
34                    CB_RANK_8,
35                    CB_RANK_7,
36                    CB_RANK_6,
37                    CB_RANK_3,
38                    CB_RANK_2,
39                    CB_RANK_1,
40                )
41            };
42
43        // Rules concerning pawns
44        value += (b.colored_pieces(color_attack, Piece::Pawn).0.count_ones() * 200) as MoveScore;
45        value -= (b.colored_pieces(color_defend, Piece::Pawn).0.count_ones() * 200) as MoveScore;
46
47        value += ((b.colored_pieces(color_attack, Piece::Pawn).0 & CB_CENTER_0_GOOD).count_ones()
48            * 15) as MoveScore;
49        value -= ((b.colored_pieces(color_defend, Piece::Pawn).0 & CB_CENTER_0_GOOD).count_ones()
50            * 15) as MoveScore;
51
52        value += ((b.colored_pieces(color_attack, Piece::Pawn).0 & CB_CENTER_1).count_ones() * 30)
53            as MoveScore;
54        value -= ((b.colored_pieces(color_defend, Piece::Pawn).0 & CB_CENTER_1).count_ones() * 30)
55            as MoveScore;
56
57        value += ((b.colored_pieces(color_attack, Piece::Pawn).0 & rank6).count_ones() * 50)
58            as MoveScore;
59        value -= ((b.colored_pieces(color_defend, Piece::Pawn).0 & rank3).count_ones() * 50)
60            as MoveScore;
61
62        value += ((b.colored_pieces(color_attack, Piece::Pawn).0 & rank7).count_ones() * 650)
63            as MoveScore;
64        value -= ((b.colored_pieces(color_defend, Piece::Pawn).0 & rank2).count_ones() * 650)
65            as MoveScore;
66
67        value -=
68            (multiple_on_file(b.colored_pieces(color_attack, Piece::Pawn).0) * 30) as MoveScore;
69        value +=
70            (multiple_on_file(b.colored_pieces(color_defend, Piece::Pawn).0) * 30) as MoveScore;
71
72        // Rules concerning knights
73        value += (b.colored_pieces(color_attack, Piece::Knight).0.count_ones() * 600) as MoveScore;
74        value -= (b.colored_pieces(color_defend, Piece::Knight).0.count_ones() * 600) as MoveScore;
75
76        value -= ((b.colored_pieces(color_attack, Piece::Knight).0 & CB_BOARD_0).count_ones() * 29)
77            as MoveScore;
78        value += ((b.colored_pieces(color_defend, Piece::Knight).0 & CB_BOARD_0).count_ones() * 29)
79            as MoveScore;
80
81        // Rules concerning bishops
82        value += (b.colored_pieces(color_attack, Piece::Bishop).0.count_ones() * 620) as MoveScore;
83        value -= (b.colored_pieces(color_defend, Piece::Bishop).0.count_ones() * 620) as MoveScore;
84
85        // Rules concerning rooks
86        value += (b.colored_pieces(color_attack, Piece::Rook).0.count_ones() * 950) as MoveScore;
87        value -= (b.colored_pieces(color_defend, Piece::Rook).0.count_ones() * 950) as MoveScore;
88
89        value += ((b.colored_pieces(color_attack, Piece::Rook).0 & b_open_files).count_ones() * 40)
90            as MoveScore;
91        value -= ((b.colored_pieces(color_defend, Piece::Rook).0 & b_open_files).count_ones() * 40)
92            as MoveScore;
93
94        value += ((b.colored_pieces(color_attack, Piece::Rook).0 & b_half_open_files).count_ones()
95            * 10) as MoveScore;
96        value -= ((b.colored_pieces(color_defend, Piece::Rook).0 & b_half_open_files).count_ones()
97            * 10) as MoveScore;
98
99        value += ((b.colored_pieces(color_attack, Piece::Rook).0 & rank7).count_ones() * 80)
100            as MoveScore;
101        value -= ((b.colored_pieces(color_defend, Piece::Rook).0 & rank2).count_ones() * 80)
102            as MoveScore;
103
104        // Rules concerning queens
105        value += (b.colored_pieces(color_attack, Piece::Queen).0.count_ones() * 1800) as MoveScore;
106        value -= (b.colored_pieces(color_defend, Piece::Queen).0.count_ones() * 1800) as MoveScore;
107
108        value -= ((b.colored_pieces(color_attack, Piece::Queen).0 & CB_CENTER).count_ones() * 30)
109            as MoveScore;
110        value += ((b.colored_pieces(color_defend, Piece::Queen).0 & CB_CENTER).count_ones() * 30)
111            as MoveScore;
112
113        if pieces_count > 20 {
114            value -= ((b.colored_pieces(color_attack, Piece::Knight).0 & rank1).count_ones() * 51)
115                as MoveScore;
116            value += ((b.colored_pieces(color_defend, Piece::Knight).0 & rank8).count_ones() * 51)
117                as MoveScore;
118
119            value -= ((b.colored_pieces(color_attack, Piece::Bishop).0 & rank1).count_ones() * 100)
120                as MoveScore;
121            value += ((b.colored_pieces(color_defend, Piece::Bishop).0 & rank8).count_ones() * 100)
122                as MoveScore;
123
124            value += ((b.colored_pieces(color_attack, Piece::Bishop).0 & CB_GOOD_BISHOP)
125                .count_ones()
126                * 20) as MoveScore;
127            value -= ((b.colored_pieces(color_defend, Piece::Bishop).0 & CB_GOOD_BISHOP)
128                .count_ones()
129                * 20) as MoveScore;
130
131            value += ((b.colored_pieces(color_attack, Piece::Queen).0 & CB_GOOD_QUEEN).count_ones()
132                * 30) as MoveScore;
133            value -= ((b.colored_pieces(color_defend, Piece::Queen).0 & CB_GOOD_QUEEN).count_ones()
134                * 30) as MoveScore;
135
136            value += ((b.colored_pieces(color_attack, Piece::King).0 & CB_SAFE_KING).count_ones()
137                * 150) as MoveScore;
138            value -= ((b.colored_pieces(color_defend, Piece::King).0 & CB_SAFE_KING).count_ones()
139                * 150) as MoveScore;
140        }
141
142        if pieces_count < 8 {
143            let mut kings_value: MoveScore = kings_distance(b) * -10;
144            kings_value -= defending_kings_moves_count(b) as MoveScore * 10;
145            kings_value -= ((b.colored_pieces(color_defend, Piece::King).0 & CB_CENTER_0)
146                .count_ones()
147                * 80) as MoveScore;
148            kings_value -= ((b.colored_pieces(color_defend, Piece::King).0 & CB_CENTER_1)
149                .count_ones()
150                * 40) as MoveScore;
151            kings_value -= ((b.colored_pieces(color_defend, Piece::King).0 & CB_BOARD_1)
152                .count_ones()
153                * 10) as MoveScore;
154            kings_value += ((b.colored_pieces(color_defend, Piece::King).0 & CB_BOARD_0)
155                .count_ones()
156                * 50) as MoveScore;
157            value += kings_value;
158        }
159
160        value
161    }
162}
163#[cfg(test)]
164mod tests {
165    use super::*;
166    use cozy_chess::Board;
167    use std::str::FromStr;
168
169    #[test]
170    fn test_evaluate() {
171        let fen = "rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1";
172        let board = Board::from_str(fen).unwrap();
173        let score = Simple::evaluate(&board);
174        assert_eq!(score, 0); // Initial position should be balanced
175
176        let fen = "rnbqkbnr/pppppppp/8/8/4P3/8/PPPP1PPP/RNBQKBNR b KQkq - 0 1";
177        let board = Board::from_str(fen).unwrap();
178        let score = Simple::evaluate(&board);
179        assert_eq!(score, -30); // White has an advantage with an extra pawn in the center, but it's black's turn
180
181        let fen = "rnbqkbnr/ppp1pppp/8/8/3Pp3/8/PPP2PPP/RNBQKBNR w KQkq - 0 1";
182        let board = Board::from_str(fen).unwrap();
183        let score = Simple::evaluate(&board);
184        assert!(score < 0); // Black has an advantage with an extra pawn in the center, but it's white's turn
185
186        let fen = "rn1qk1nr/pppbbppp/8/3pp3/3PP3/1P4P1/PBP2PBP/RN1QK1NR w KQkq - 0 1";
187        let board = Board::from_str(fen).unwrap();
188        let score = Simple::evaluate(&board);
189        assert!(score > 0); // White has positional advantage and it's white's turn
190
191        let fen = "rn1qk1nr/pppbbppp/8/3pp3/3PP3/1P4P1/PBP2PBP/RN1QK1NR b KQkq - 0 1";
192        let board = Board::from_str(fen).unwrap();
193        let score = Simple::evaluate(&board);
194        assert!(score < 0); // White has positional advantage but it's black's turn
195
196        let fen = "rn1qk1nr/pbp2pbp/1p4p1/3pp3/3PP3/8/PPPBBPPP/RN1QK1NR w KQkq - 0 1";
197        let board = Board::from_str(fen).unwrap();
198        let score = Simple::evaluate(&board);
199        assert!(score < 0); // Black has positional advantage but it's white's turn
200
201        let fen = "rn1qk1nr/pbp2pbp/1p4p1/3pp3/3PP3/8/PPPBBPPP/RN1QK1NR b KQkq - 0 1";
202        let board = Board::from_str(fen).unwrap();
203        let score = Simple::evaluate(&board);
204        assert!(score > 0); // Black has positional advantage and it's black's turn
205
206        let fen_n = "8/8/4k3/8/3R4/4K3/8/8 w - - 0 1";
207        let fen_f = "8/8/4k3/8/3R4/8/8/4K3 w - - 0 1";
208        let board_n = Board::from_str(fen_n).unwrap();
209        let board_f = Board::from_str(fen_f).unwrap();
210        let score_n = Simple::evaluate(&board_n);
211        let score_f = Simple::evaluate(&board_f);
212        assert!(score_n > score_f); // Nearer king is better for stronger party
213
214        let fen_n = "8/8/4k3/8/3R4/4K3/8/8 b - - 0 1";
215        let fen_f = "8/8/4k3/8/3R4/8/8/4K3 b - - 0 1";
216        let board_n = Board::from_str(fen_n).unwrap();
217        let board_f = Board::from_str(fen_f).unwrap();
218        let score_n = Simple::evaluate(&board_n);
219        let score_f = Simple::evaluate(&board_f);
220        assert!(score_n < score_f); // Nearer king is worse for weaker party
221
222        let fen_n = "8/8/5b2/5b2/5k2/8/8/5K2 b - - 0 1";
223        let fen_f = "8/5k2/5b2/5b2/8/8/8/5K2 b - - 0 1";
224        let board_n = Board::from_str(fen_n).unwrap();
225        let board_f = Board::from_str(fen_f).unwrap();
226        let score_n = Simple::evaluate(&board_n);
227        let score_f = Simple::evaluate(&board_f);
228        assert!(score_n > score_f); // Nearer king is better for stronger party
229
230        let fen_n = "8/8/5b2/5b2/5k2/8/8/5K2 w - - 0 1";
231        let fen_f = "8/5k2/5b2/5b2/8/8/8/5K2 w - - 0 1";
232        let board_n = Board::from_str(fen_n).unwrap();
233        let board_f = Board::from_str(fen_f).unwrap();
234        let score_n = Simple::evaluate(&board_n);
235        let score_f = Simple::evaluate(&board_f);
236        assert!(score_n < score_f); // Nearer king is worse for weaker party
237    }
238}