hexe_core/board/multi_board/
mod.rs1use core::{hash, ops, mem};
4
5#[cfg(feature = "simd")]
6use core::simd::u8x64;
7
8use board::{Bitboard, PieceMap};
9use castle::Right;
10use color::Color;
11use piece::{Piece, Role};
12use square::Square;
13use uncon::*;
14
15#[cfg(all(test, nightly))]
16mod benches;
17
18#[cfg(test)]
19mod tests;
20
21mod values {
22 use super::*;
23
24 const PAWN: u64 = 0x00FF00000000FF00;
25 const KNIGHT: u64 = squares!(B1, B8, G1, G8);
26 const BISHOP: u64 = squares!(C1, C8, F1, F8);
27 const ROOK: u64 = squares!(A1, A8, H1, H8);
28 const QUEEN: u64 = squares!(D1, D8);
29 const KING: u64 = squares!(E1, E8);
30 const WHITE: u64 = 0x000000000000FFFF;
31 const BLACK: u64 = 0xFFFF000000000000;
32
33 pub const STANDARD: MultiBoard = MultiBoard {
34 pieces: [PAWN, KNIGHT, BISHOP, ROOK, QUEEN, KING],
35 colors: [WHITE, BLACK],
36 };
37}
38
39const NUM_PIECES: usize = 6;
40const NUM_COLORS: usize = 2;
41const NUM_BOARDS: usize = NUM_PIECES + NUM_COLORS;
42const NUM_BYTES: usize = NUM_BOARDS * 8;
43
44#[repr(C)]
46#[derive(Clone, Eq)]
47pub struct MultiBoard {
48 pieces: [u64; NUM_PIECES],
49 colors: [u64; NUM_COLORS],
50}
51
52impl PartialEq for MultiBoard {
53 #[inline]
54 fn eq(&self, other: &Self) -> bool {
55 #[cfg(feature = "simd")]
56 {
57 self as *const _ == other as *const _ || self.simd() == other.simd()
58 }
59 #[cfg(not(feature = "simd"))]
60 {
61 self.bytes()[..] == other.bytes()[..]
62 }
63 }
64}
65
66impl Default for MultiBoard {
67 #[inline]
68 fn default() -> MultiBoard {
69 unsafe { mem::zeroed() }
70 }
71}
72
73impl AsRef<[u64]> for MultiBoard {
74 #[inline]
75 fn as_ref(&self) -> &[u64] {
76 let array = self as *const _ as *const [_; NUM_BOARDS];
77 unsafe { &*array }
78 }
79}
80
81impl AsMut<[u64]> for MultiBoard {
82 #[inline]
83 fn as_mut(&mut self) -> &mut [u64] {
84 let array = self as *mut _ as *mut [_; NUM_BOARDS];
85 unsafe { &mut *array }
86 }
87}
88
89impl AsRef<[Bitboard]> for MultiBoard {
90 #[inline]
91 fn as_ref(&self) -> &[Bitboard] {
92 let array = self as *const _ as *const [_; NUM_BOARDS];
93 unsafe { &*array }
94 }
95}
96
97impl AsMut<[Bitboard]> for MultiBoard {
98 #[inline]
99 fn as_mut(&mut self) -> &mut [Bitboard] {
100 let array = self as *mut _ as *mut [_; NUM_BOARDS];
101 unsafe { &mut *array }
102 }
103}
104
105impl<'a> From<&'a PieceMap> for MultiBoard {
106 fn from(map: &PieceMap) -> MultiBoard {
107 let mut board = MultiBoard::default();
108 for (square, &piece) in map {
109 board.insert_unchecked(square, piece);
110 }
111 board
112 }
113}
114
115impl hash::Hash for MultiBoard {
116 #[inline]
117 fn hash<H: hash::Hasher>(&self, state: &mut H) {
118 state.write(self.bytes());
119 }
120}
121
122impl ops::Index<Role> for MultiBoard {
123 type Output = Bitboard;
124
125 #[inline]
126 fn index(&self, role: Role) -> &Bitboard {
127 Bitboard::convert_ref(&self.pieces[role as usize])
128 }
129}
130
131impl ops::IndexMut<Role> for MultiBoard {
132 #[inline]
133 fn index_mut(&mut self, role: Role) -> &mut Bitboard {
134 Bitboard::convert_mut(&mut self.pieces[role as usize])
135 }
136}
137
138impl ops::Index<Color> for MultiBoard {
139 type Output = Bitboard;
140
141 #[inline]
142 fn index(&self, color: Color) -> &Bitboard {
143 Bitboard::convert_ref(&self.colors[color as usize])
144 }
145}
146
147impl ops::IndexMut<Color> for MultiBoard {
148 #[inline]
149 fn index_mut(&mut self, color: Color) -> &mut Bitboard {
150 Bitboard::convert_mut(&mut self.colors[color as usize])
151 }
152}
153
154impl MultiBoard {
155 pub const STANDARD: MultiBoard = values::STANDARD;
157
158 #[cfg(feature = "simd")]
159 #[inline]
160 fn simd(&self) -> u8x64 {
161 u8x64::load_unaligned(self.bytes())
162 }
163
164 #[inline]
165 fn bytes(&self) -> &[u8; NUM_BYTES] {
166 unsafe { self.into_unchecked() }
167 }
168
169 #[inline]
171 pub fn clear(&mut self) {
172 unsafe { ::util::zero(self) }
173 }
174
175 #[inline]
191 pub fn is_empty(&self) -> bool {
192 self.all_bits().is_empty()
193 }
194
195 #[inline]
208 pub fn len(&self) -> usize {
209 self.all_bits().len()
210 }
211
212 #[inline]
227 pub fn all_bits(&self) -> Bitboard {
228 Bitboard(self.colors[0] | self.colors[1])
229 }
230
231 #[inline]
247 pub fn bitboard<T: Index>(&self, value: T) -> Bitboard {
248 value.bitboard(self)
249 }
250
251 #[inline]
253 pub fn royals(&self) -> Bitboard {
254 self.bitboard(Role::Queen) | self.bitboard(Role::King)
255 }
256
257 #[inline]
259 pub fn first<T: Index>(&self, value: T) -> Option<Square> {
260 self.bitboard(value).lsb()
261 }
262
263 #[inline]
266 pub unsafe fn first_unchecked<T: Index>(&self, value: T) -> Square {
267 self.bitboard(value).lsb_unchecked()
268 }
269
270 #[inline]
272 pub fn last<T: Index>(&self, value: T) -> Option<Square> {
273 self.bitboard(value).msb()
274 }
275
276 #[inline]
279 pub unsafe fn last_unchecked<T: Index>(&self, value: T) -> Square {
280 self.bitboard(value).msb_unchecked()
281 }
282
283 #[inline]
300 pub fn count<T: Index>(&self, value: T) -> usize {
301 self.bitboard(value).len()
302 }
303
304 #[inline]
321 pub fn contains<T, U>(&self, bits: T, value: U) -> bool
322 where T: Into<Bitboard>, U: Index
323 {
324 self.bitboard(value).contains(bits)
325 }
326
327 #[inline]
343 pub fn contains_any<T, U>(&self, bits: T, value: U) -> bool
344 where T: Into<Bitboard>, U: Index
345 {
346 !(self.bitboard(value) & bits).is_empty()
347 }
348
349 #[inline]
352 pub fn insert<T: Into<Bitboard>>(&mut self, bits: T, piece: Piece) {
353 let value = bits.into();
354 self.remove_all(value);
355 self.insert_unchecked(value, piece);
356 }
357
358 #[inline]
364 pub fn insert_unchecked<T: Into<Bitboard>>(&mut self, bits: T, piece: Piece) {
365 let value = bits.into();
366 self[piece.color()] |= value;
367 self[piece.role() ] |= value;
368 }
369
370 #[inline]
372 pub fn remove<T, U>(&mut self, bits: T, value: U)
373 where T: Into<Bitboard>, U: Index
374 {
375 value.remove(bits, self);
376 }
377
378 #[inline]
383 pub fn remove_unchecked<T, U>(&mut self, bits: T, value: U)
384 where T: Into<Bitboard>, U: Index
385 {
386 value.remove_unchecked(bits, self);
387 }
388
389 #[inline]
413 pub fn remove_all<T: Into<Bitboard>>(&mut self, bits: T) {
414 let value = !bits.into().0;
415 for board in AsMut::<[u64]>::as_mut(self) {
416 *board &= value;
417 }
418 }
419
420 #[inline]
423 pub fn split(&self) -> (&[Bitboard; NUM_COLORS], &[Bitboard; NUM_PIECES]) {
424 let colors = &self.colors as *const _ as *const _;
425 let pieces = &self.pieces as *const _ as *const _;
426 unsafe { (&*colors, &*pieces) }
427 }
428
429 #[inline]
432 pub fn split_mut(&mut self) -> (&mut [Bitboard; NUM_COLORS], &mut [Bitboard; NUM_PIECES]) {
433 let colors = &mut self.colors as *mut _ as *mut _;
434 let pieces = &mut self.pieces as *mut _ as *mut _;
435 unsafe { (&mut *colors, &mut *pieces) }
436 }
437
438 pub fn is_attacked(&self, sq: Square, player: Color) -> bool {
443 macro_rules! check {
444 ($e:expr) => { if $e { return true } };
445 }
446
447 let opp = self.bitboard(!player);
448 let all = opp | self.bitboard(player);
449
450 let pawns = opp & self.bitboard(Role::Pawn);
451 check!(pawns.intersects(sq.pawn_attacks(player)));
452
453 let knights = opp & self.bitboard(Role::Knight);
454 check!(knights.intersects(sq.knight_attacks()));
455
456 let kings = opp & (self.bitboard(Role::King));
457 check!(kings.intersects(sq.king_attacks()));
458
459 let queens = self.bitboard(Role::Queen);
460
461 let bishops = opp & (self.bitboard(Role::Bishop) | queens);
462 check!(bishops.intersects(sq.bishop_attacks(all)));
463
464 let rooks = opp & (self.bitboard(Role::Rook) | queens);
465 rooks.intersects(sq.rook_attacks(all))
466 }
467
468 #[inline]
538 pub fn castle(&mut self, right: Right) {
539 static MASKS: [(u64, u64); 4] = [
541 (squares!(E1, G1), squares!(H1, F1)),
542 (squares!(E1, C1), squares!(A1, D1)),
543 (squares!(E8, G8), squares!(H8, F8)),
544 (squares!(E8, C8), squares!(A8, D8)),
545 ];
546
547 let (king, rook) = MASKS[right as usize];
548 self[right.color()] ^= king | rook;
549 self[Role::King] ^= king;
550 self[Role::Rook] ^= rook;
551 }
552}
553
554pub trait Index {
557 fn bitboard(self, board: &MultiBoard) -> Bitboard;
559
560 fn remove<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard);
562
563 fn remove_unchecked<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard);
565}
566
567impl Index for Color {
568 #[inline]
569 fn bitboard(self, board: &MultiBoard) -> Bitboard {
570 board[self]
571 }
572
573 #[inline]
574 fn remove<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
575 self.remove_unchecked(board[self] & bits.into(), board);
576 }
577
578 #[inline]
579 fn remove_unchecked<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
580 let value = !bits.into().0;
581 board[self] &= value;
582 for piece in &mut board.pieces {
583 *piece &= value;
584 }
585 }
586}
587
588impl Index for Piece {
589 #[inline]
590 fn bitboard(self, board: &MultiBoard) -> Bitboard {
591 self.color().bitboard(board) & self.role().bitboard(board)
592 }
593
594 #[inline]
595 fn remove<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
596 let value = board[self.color()] | board[self.role()];
597 self.remove_unchecked(value & bits.into(), board);
598 }
599
600 #[inline]
601 fn remove_unchecked<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
602 let value = !bits.into().0;
603 board[self.color()] &= value;
604 board[self.role() ] &= value;
605 }
606}
607
608impl Index for Role {
609 #[inline]
610 fn bitboard(self, board: &MultiBoard) -> Bitboard {
611 board[self]
612 }
613
614 #[inline]
615 fn remove<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
616 self.remove_unchecked(board[self] & bits.into(), board);
617 }
618
619 #[inline]
620 fn remove_unchecked<T: Into<Bitboard>>(self, bits: T, board: &mut MultiBoard) {
621 let value = !bits.into().0;
622 board[self] &= value;
623 for color in &mut board.colors {
624 *color &= value;
625 }
626 }
627}