1use std::{convert::TryFrom, iter::zip};
2use bulletformat::ChessBoard;
3
4#[repr(u8)]
5#[allow(dead_code)]
6#[derive(Copy, Clone, Eq, PartialEq)]
7pub enum PieceType{
8 Pawn,
9 Knight,
10 Bishop,
11 Rook,
12 Queen,
13 King,
14 Castle,
15 Void
16}
17
18#[repr(u8)]
19#[allow(dead_code)]
20#[derive(Copy, Clone, Eq, PartialEq)]
21pub enum Pieces{
22 WPawn, BPawn,
23 WKnight, BKnight,
24 WBishop, BBishop,
25 WRook, BRook,
26 WQueen, BQueen,
27 WKing, BKing,
28 WCASTLE, BCASLTE,
29 Void
30}
31
32#[allow(dead_code)]
33pub enum Color{White, Black}
34
35impl TryFrom<u8> for Color {
36 type Error = ();
37
38 fn try_from(v: u8) -> Result<Self, Self::Error> {
39 unsafe { std::mem::transmute(v) }
40 }
41}
42
43impl TryFrom<u8> for PieceType {
44 type Error = ();
45
46 fn try_from(v: u8) -> Result<Self, Self::Error> {
47 unsafe { std::mem::transmute(v) }
48 }
49}
50
51impl Pieces {
52 pub fn color(&self) -> Color {
53 (*self as u8 % 2).try_into().unwrap()
54 }
55 pub fn piecetype(&self) -> PieceType {
56 (*self as u8 / 2).try_into().unwrap()
57 }
58 pub fn from_viri(id: u8) -> Pieces {
59 ((id >> 3) | (id & 0b111) << 1).try_into().unwrap()
60 }
61 pub fn from_pc_color(pc: PieceType, c: Color) -> Pieces {
62 ((pc as u8) << 1 | c as u8).try_into().unwrap()
63 }
64}
65
66impl TryFrom<u8> for Pieces {
67 type Error = ();
68
69 fn try_from(v: u8) -> Result<Self, Self::Error> {
70 unsafe { std::mem::transmute(v) }
71 }
72}
73const ZOBR_CASTLE: usize = 12*64;
74const ZOBR_PASSANT: usize = ZOBR_CASTLE;
75const ZOBR_TURN: usize = ZOBR_PASSANT+65;
76#[cfg(feature = "hll")]
77const ZOBR_TOT: usize = ZOBR_TURN+1;
78#[cfg(feature = "hll")]
79const ZOBRISTS: [u64; ZOBR_TOT] = {
80 let mut res: [u64; ZOBR_TOT] = [0; ZOBR_TOT];
81
82 let mut state: u64 = 42;
83 cfor!(let mut idz: usize = 0; idz < ZOBR_TOT; idz += 1; {
84 state = state.wrapping_add(0x9E3779B97F4A7C15);
85 let mut z: u64 = state;
86 z = (z ^ (z >> 30)).wrapping_mul(0xBF58476D1CE4E5B9);
87 z = (z ^ (z >> 27)).wrapping_mul(0x94D049BB133111EB);
88 res[idz] = z ^ (z >> 31);
89 });
90 res[ZOBR_CASTLE+64] = 0;
91 res[ZOBR_PASSANT+64] = 0;
92 res
93};
94
95#[derive(Clone, Copy)]
96pub struct Position{
97 pub bbs: [u64; 8],
98 pub mailbox: [u8; 64],
99 pub score: i16,
100 pub bound: u8,
101 pub rule50: u8,
102 pub bm: u16,
103 pub stm: bool,
104 pub depth: u8,
105 pub ep: u8,
106 pub castle_mask: u64,
107 #[cfg(feature = "hll")]
108 pub hash: u64,
109}
110
111impl Default for Position {
112 fn default() -> Self {
113 Self {
114 bbs: [0; 8],
115 mailbox: [Pieces::Void as u8; 64],
116 score: 0,
117 bound: 0,
118 rule50: 0,
119 bm: 0,
120 stm: true,
121 depth: 0,
122 ep: 64,
123 castle_mask: 0,
124 #[cfg(feature = "hll")]
125 hash: 0,
126 }
127 }
128}
129
130const KINGPOS_CASTLE: [u8; 2] = [2, 6];
131const ROOKPOS_CASTLE: [u8; 2] = [3, 5];
132
133impl Position {
134 pub fn piece(&self, idx: usize) -> Pieces {
135 self.mailbox[idx].try_into().unwrap()
136 }
137 fn update_zobr(&mut self, _idx: usize) {
138#[cfg(feature = "hll")]
139{
140 self.hash ^= ZOBRISTS[_idx];
141}
142 }
143
144 #[allow(dead_code)]
145 pub fn print(&self) {
146 for i in 0..64 {
147 if self.mailbox[i]/2 == 7 {
148 print!("## ");
149 }else {
150 print!("{:2} ", self.mailbox[i]);
151 }
152 if i % 8 == 7 {
153 print!("\n");
154 }
155 }
156 }
157
158 pub fn push(&mut self, idx: u32, piece: Pieces) {
159 assert!(self.mailbox[idx as usize] == Pieces::Void as u8);
160 self.mailbox[idx as usize] = piece as u8;
161 self.bbs[piece.color() as usize] |= 1_u64 << idx;
162 self.bbs[piece.piecetype() as usize + 2] |= 1_u64 << idx;
163 self.update_zobr((piece as u32 * 64 + idx) as usize);
164 }
165
166 pub fn update_ep(&mut self, newep: usize) {
167 self.update_zobr(newep + ZOBR_PASSANT);
168 self.ep = newep as u8;
169 }
170 pub fn update_stm(&mut self, newstm: usize) {
171 #[cfg(feature = "hll")]
172 if newstm != 0 {
173 self.hash ^= ZOBRISTS[ZOBR_TURN];
174 }
175 self.stm = newstm != 0;
176 }
177 pub fn turn_stm(&mut self) {
178 self.update_zobr(ZOBR_TURN);
179 self.stm = !self.stm;
180 }
181 pub fn update_castle_rights(&mut self, castle_idx: usize) {
182 self.update_zobr(castle_idx + ZOBR_CASTLE);
183 self.castle_mask |= 1 << castle_idx as u64;
184 }
185
186 fn erase(&mut self, idx: usize){
187 let erased: Pieces = self.piece(idx);
188 if erased != Pieces::Void {
189 self.bbs[erased.piecetype() as usize + 2] ^= 1_u64 << idx;
190 self.bbs[erased.color() as usize] ^= 1_u64 << idx;
191 self.update_zobr(erased as usize * 64 + idx);
192 }
193 self.mailbox[idx] = Pieces::Void as u8;
194 }
195
196 fn erasesure(&mut self, idx: usize){
197 let erased: Pieces = self.piece(idx);
198 self.bbs[erased.piecetype() as usize + 2] ^= 1_u64 << idx;
199 self.bbs[erased.color() as usize] ^= 1_u64 << idx;
200 self.update_zobr(erased as usize * 64 + idx);
201 self.mailbox[idx] = Pieces::Void as u8;
202 }
203
204 #[allow(dead_code)]
205 fn verify(&self) -> bool { #[cfg(feature = "hll")]
207 {
208 let mut zobr: u64 = 0;
209 for i in 0..64 {
210 if self.mailbox[i] != Pieces::Void as u8 {
211 zobr ^= ZOBRISTS[i + 64 * self.mailbox[i] as usize];
212 }
213 }
214 zobr ^= ZOBRISTS[ZOBR_TURN] * self.stm as u64;
215 let mut mask = self.castle_mask;
216 while mask != 0 {
217 zobr ^= ZOBRISTS[ZOBR_CASTLE + mask.trailing_zeros() as usize];
218 mask &= mask-1;
219 }
220 zobr ^= ZOBRISTS[ZOBR_PASSANT + self.ep as usize];
221 if zobr != self.hash {
222 return false;
223 }
224 }
225 let mut newbbs: [u64; 8] = [0; 8];
226 for i in 0..64 {
227 if self.mailbox[i] != Pieces::Void as u8 {
228 newbbs[self.mailbox[i] as usize % 2] |= 1_u64 << i;
229 newbbs[self.mailbox[i] as usize / 2 + 2] |= 1_u64 << i;
230 }
231 }
232 for (n, o) in zip(newbbs, self.bbs) {
233 if n != o {
234 return false;
235 }
236 }
237 true
238 }
239
240 pub fn play(&mut self, mv: u16) {
241 let from = (mv & 0x3f) as u8;
242 let to = ((mv >> 6) & 0x3f) as u8;
243 let promo = (mv >> 12) & 0b11;
244 let flag = mv >> 14;
245 let piece: Pieces = self.piece(from as usize);
246 assert!(piece != Pieces::Void);
247 let capture: Pieces = self.piece(to as usize);
248 let _reset: bool = (capture != Pieces::Void && flag != 2) || piece.piecetype() == PieceType::Pawn;
249 if flag == 0 {
253
254 let masktofrom: u64 =
255 (1_u64 << to as u64) | (1_u64 << from as u64) |
256 (piece.piecetype() == PieceType::King) as u64 * (0xff_u64 << piece.color() as u64 * 56);
257
258 let mut mask: u64 = self.castle_mask & masktofrom;
259 self.castle_mask ^= mask;
260
261 self.update_zobr(ZOBR_CASTLE + mask.trailing_zeros() as usize);
262 mask &= mask.wrapping_sub(1);
263
264 self.update_zobr(ZOBR_CASTLE + mask.trailing_zeros() as usize);
265
266 self.update_zobr(self.ep as usize + ZOBR_PASSANT);
267 self.ep = (piece.piecetype() == PieceType::Pawn && ((to ^ from) & 0b10_000) != 0) as u8 * to as u8;
268 self.ep += 64*(self.ep == 0) as u8;
269
270 self.update_zobr(self.ep as usize + ZOBR_PASSANT);
271
272 self.erasesure(from as usize);
273 self.erase(to as usize);
274 self.push(to as u32, piece);
275 } else if flag == 1 {
276 assert!(self.ep < 64);
277 assert!(self.mailbox[self.ep as usize]/2 == 0);
278 self.erasesure(from as usize);
279 self.erasesure(self.ep as usize);
280 self.push(to as u32, piece);
281 self.update_zobr(self.ep as usize + ZOBR_PASSANT);
282 self.ep = 64;
283 } else if flag == 2 {
284
285 let to_king = (from&56) | KINGPOS_CASTLE[(from < to) as usize];
286 let to_rook = (from&56) | ROOKPOS_CASTLE[(from < to) as usize];
287
288 let mut mask: u64 = (0xff << (from & 56) as u64) & self.castle_mask;
289 self.castle_mask ^= mask;
290 self.update_zobr(ZOBR_CASTLE + mask.trailing_zeros() as usize);
291 mask &= mask.wrapping_sub(1);
292 self.update_zobr(ZOBR_CASTLE + mask.trailing_zeros() as usize);
293
294 self.erasesure(from as usize);
295 self.erasesure(to as usize);
296 self.push(to_king as u32, piece);
297 self.push(to_rook as u32, Pieces::from_pc_color(PieceType::Rook, piece.color()));
298
299 self.update_zobr(self.ep as usize + ZOBR_PASSANT);
300 self.ep = 64;
301 } else {
302 assert!(flag == 3);
303 let to_piece = Pieces::from_pc_color(((promo+1) as u8).try_into().unwrap(), piece.color());
304 if capture.piecetype() == PieceType::Rook && (self.castle_mask & (1 << to as u64) != 0){
305 self.update_zobr(ZOBR_CASTLE + to as usize);
306 self.castle_mask &= !(1 << to as u64);
307 }
308 self.update_zobr(self.ep as usize + ZOBR_PASSANT);
309 self.ep = 64;
310
311 self.erasesure(from as usize);
312 self.erase(to as usize);
313 self.push(to as u32, to_piece);
314 }
315
316 self.turn_stm();
317 }
322
323 pub fn tobullet(&self) -> ChessBoard {
324 let mut res = ChessBoard::from_raw(self.bbs, self.stm as usize, self.score, self.bound as f32).unwrap();
325 res.result = self.bound;
326 res.score = self.score;
327 res
328 }
329}