1#![allow(unused_must_use)]
2use crate::piece_color::PieceColor;
3use crate::position_move::PositionMove;
4use crate::BoardMap;
5use rand::Rng;
6
7#[derive(Default, Clone)]
8pub struct ChessEngine {}
9
10impl ChessEngine {
11 const MIN: f32 = -1000.;
12 const MAX: f32 = 1000.;
13
14 pub fn find_best_move_minimax_ab(&mut self, board: BoardMap, depth: usize) -> PositionMove {
15 let mut best_value = Self::MIN;
16 let mut best_moves = vec![];
17 for from in board.get_active_pieces() {
18 let moves = board.gen_legal_positions(from);
19 for to in moves {
20 let piece_move = PositionMove::new(from, to);
21 let piece_value = board.get_piece(from).0;
22 let mut temp_board = board;
23
24 temp_board.single_move_turn(piece_move);
25 let move_value =
26 self.ab_max(depth, temp_board, ChessEngine::MIN, ChessEngine::MAX, true);
27 temp_board.undo_move(piece_move, piece_value);
28
29 if move_value == best_value {
30 best_moves.push(piece_move);
31 } else if move_value > best_value {
32 best_value = move_value;
33 best_moves.clear();
34 best_moves.push(piece_move);
35 }
36 }
37 }
38
39 println!("best move value is {}", best_value);
40 println!(
41 "possible moves are {:?}",
42 best_moves
43 .iter()
44 .map(|x| format!("{:?} to {:?}", x.from, x.to))
45 .collect::<Vec<_>>()
46 );
47
48 let mut rand = rand::thread_rng();
49 let index = rand.gen_range(0..best_moves.len());
50 best_moves[index]
51 }
52
53 pub fn find_best_move_negamax(&mut self, board: BoardMap, depth: usize) -> PositionMove {
54 let mut best_value = Self::MIN;
55 let mut best_moves = vec![];
56 for from in board.get_active_pieces() {
57 let moves = board.gen_legal_positions(from);
58 for to in moves {
59 let piece_move = PositionMove::new(from, to);
60 let piece_value = board.get_piece(from).0;
61
62 let mut temp_board = board;
63 temp_board.single_move_turn(piece_move);
64 let move_value = self.nega_max(temp_board, depth);
65 temp_board.undo_move(piece_move, piece_value);
66
67 if move_value == best_value {
68 best_moves.push(piece_move);
69 } else if move_value > best_value {
70 best_value = move_value;
71 best_moves.clear();
72 best_moves.push(piece_move);
73 }
74 }
75 }
76
77 println!("best move value is {}", best_value);
78 println!(
79 "possible moves are {:?}",
80 best_moves
81 .iter()
82 .take(10)
83 .map(|x| format!("{:?} to {:?}", x.from, x.to))
84 .collect::<Vec<_>>()
85 );
86
87 let mut rand = rand::thread_rng();
88 let index = rand.gen_range(0..best_moves.len());
89 best_moves[index]
90 }
91
92 fn ab_max(
93 &self,
94 depth: usize,
95 board: BoardMap,
96 mut alpha: f32,
97 mut beta: f32,
98 is_maximizing_player: bool,
99 ) -> f32 {
100 if is_maximizing_player {
101 if depth == 0 {
103 return self.evaluate(board);
104 }
105 let moves = board.gen_all_legal_moves();
106
107 for piece_move in moves.iter() {
108 let mut temp_board = board;
109
110 let piece_value = board.get_piece(piece_move.from).0;
111
112 temp_board.single_move_turn(*piece_move);
113 let score = self.ab_max(depth - 1, temp_board, alpha, beta, !is_maximizing_player);
114 temp_board.undo_move(*piece_move, piece_value);
115
116 if score >= beta {
117 return beta;
118 }
119 if score > alpha {
120 alpha = score;
121 }
122 }
123 alpha
124 } else {
125 if depth == 0 {
127 return -self.evaluate(board);
128 }
129 let moves = board.gen_all_legal_moves();
130
131 for piece_move in moves.iter() {
132 let mut temp_board = board;
133
134 let piece_value = board.get_piece(piece_move.from).0;
135
136 temp_board.single_move_turn(*piece_move);
137 let score = self.ab_max(depth - 1, temp_board, alpha, beta, !is_maximizing_player);
138 temp_board.undo_move(*piece_move, piece_value);
139
140 if score <= alpha {
141 return alpha;
142 }
143 if score < beta {
144 beta = score;
145 }
146 }
147 beta
148 }
149 }
150
151 fn nega_max(&mut self, board: BoardMap, depth: usize) -> f32 {
152 if depth == 0 {
153 return self.evaluate(board);
154 }
155 let mut max = Self::MIN;
156 let moves = board.gen_all_legal_moves();
157
158 for piece_move in moves.iter() {
159 let mut temp_board = board;
160 temp_board.single_move_turn(*piece_move);
161
162 let value = -self.nega_max(board, depth - 1);
163 if value > max {
164 max = value;
165 }
166 }
167 max
168 }
169
170 fn evaluate(&self, board: BoardMap) -> f32 {
175 let material_weight = board.get_material_weight() as f32;
176 let num_white_pieces = board.get_num_white_pieces() as f32;
177 let num_black_pieces = board.get_num_black_pieces() as f32;
178 let who2move = if *board.get_active_color() == PieceColor::Black {
179 1.
180 } else {
181 -1.
182 };
183 material_weight * (num_white_pieces - num_black_pieces) * who2move
185 }
186}