1use thiserror::Error;
2
3use crate::bitboard::BitBoard;
4use crate::position::{MoveIter, Square};
5use crate::turn::Turn;
6
7const INITIAL_RED_PIECES: BitBoard = BitBoard::new(0x2AD5AA);
8const INITIAL_BLACK_PIECES: BitBoard = BitBoard::new(0x156AD50000000000);
9const INITIAL_KINGS: BitBoard = BitBoard::new(0x0);
10
11#[derive(Debug, Error)]
12pub enum MoveError {}
13
14#[derive(PartialEq, Debug)]
16pub enum BoardStatus {
17 OnGoing,
20
21 Complete,
24}
25
26#[derive(PartialEq, Debug, Copy, Clone)]
28pub enum Player {
29 Red,
30 Black,
31}
32
33impl Default for Board {
34 fn default() -> Self {
36 Board {
37 current_player: Player::Black,
38 red_pieces: INITIAL_RED_PIECES,
39 black_pieces: INITIAL_BLACK_PIECES,
40 kings: INITIAL_KINGS,
41 }
42 }
43}
44
45#[derive(Debug)]
46pub struct Board {
47 current_player: Player,
48 red_pieces: BitBoard,
49 black_pieces: BitBoard,
50 kings: BitBoard,
51}
52
53impl Board {
54 pub fn empty() -> Self {
56 Board {
57 red_pieces: BitBoard::new(0),
58 black_pieces: BitBoard::new(0),
59 kings: BitBoard::new(0),
60 ..Board::default()
61 }
62 }
63
64 pub fn current_player(&self) -> Player { self.current_player }
66
67 pub fn status(&self) -> BoardStatus {
70 let mut player_moves = MoveIter::new(self, self.current_player);
71 match player_moves.next() {
72 Some(_) => BoardStatus::OnGoing,
73 None => BoardStatus::Complete
74 }
75 }
76
77 pub fn push_turn(&mut self, turn: Turn) -> Result<(), MoveError> {
80 todo!()
81 }
82
83 pub fn pop_turn(&mut self) {
85 todo!()
86 }
87
88 pub fn red_pieces(&self) -> BitBoard {
90 self.red_pieces
91 }
92
93 pub fn black_pieces(&self) -> BitBoard {
95 self.black_pieces
96 }
97
98 pub fn pieces_by_player(&self, player: Player) -> BitBoard {
100 match player {
101 Player::Red => self.red_pieces,
102 Player::Black => self.black_pieces
103 }
104 }
105
106 pub fn all_pieces(&self) -> BitBoard {
108 self.red_pieces | self.black_pieces
109 }
110
111 pub fn red_kings(&self) -> BitBoard {
113 self.red_pieces & self.kings
114 }
115
116 pub fn black_kings(&self) -> BitBoard {
118 self.black_pieces & self.kings
119 }
120
121 pub fn kings_by_player(&self, player: Player) -> BitBoard {
123 match player {
124 Player::Red => self.red_kings(),
125 Player::Black => self.black_kings()
126 }
127 }
128
129 pub fn all_kings(&self) -> BitBoard { self.kings }
131
132 pub fn direction(&self) -> i8 {
136 match self.current_player {
137 Player::Red => 1,
138 Player::Black => -1
139 }
140 }
141}
142
143#[derive(Debug, Error, PartialEq)]
144pub enum BoardCreationError {
145 #[error("Only a single piece can be placed per square.")]
146 DuplicateSquareAssignments
147}
148
149#[derive(Debug)]
150struct Placement {
151 player: Player,
152 square: Square,
153 is_king: bool,
154}
155
156#[derive(Debug)]
158pub struct BoardBuilder {
159 current_player: Player,
160 placements: Vec<Placement>,
161}
162
163impl BoardBuilder {
164 pub fn current_player(&mut self, player: Player) -> &mut Self {
166 self.current_player = player;
167 self
168 }
169
170 pub fn place_piece(&mut self, player: Player, square: Square) -> &mut Self {
172 let placement = Placement { player, square, is_king: false };
173 self.placements.push(placement);
174 self
175 }
176
177 pub fn place_king(&mut self, player: Player, square: Square) -> &mut Self {
179 let placement = Placement { player, square, is_king: true };
180 self.placements.push(placement);
181 self
182 }
183
184 pub fn build(&self) -> Result<Board, BoardCreationError> {
188 let current_player = self.current_player;
189 let mut red_pieces = BitBoard::new(0);
190 let mut black_pieces = BitBoard::new(0);
191 let mut kings = BitBoard::new(0);
192 for placement in &self.placements {
193 let piece = placement.square.to_bitboard();
194 if (red_pieces | black_pieces).contains(piece) {
195 return Err(BoardCreationError::DuplicateSquareAssignments);
196 }
197
198 match placement.player {
199 Player::Red => { red_pieces = red_pieces | piece }
200 Player::Black => { black_pieces = black_pieces | piece }
201 }
202
203 if placement.is_king {
204 kings = kings | piece
205 }
206 }
207
208 let board = Board { current_player, red_pieces, black_pieces, kings };
209 Ok(board)
210 }
211}
212
213impl Default for BoardBuilder {
214 fn default() -> Self {
215 BoardBuilder {
216 current_player: Player::Black,
217 placements: vec![],
218 }
219 }
220}