bitfield boards are workin great
This commit is contained in:
parent
b2ea4fd2f3
commit
8a61a3aedc
|
@ -0,0 +1,164 @@
|
||||||
|
// Bitpacked board:
|
||||||
|
// One piece can be represented with 4 bits. Therefore, we can fit two pieces in one byte:
|
||||||
|
// 0b0110_1110 -
|
||||||
|
// | \
|
||||||
|
// Black king \- White king
|
||||||
|
// As there are 64 spaces on the board, we can pack the board into a 256-bit integer, and we use that as the index for transposition tables and such.
|
||||||
|
// Boards are stored as two 128-bit bitfields, to make accessing them as efficient as possible.
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
a b c d e f g h
|
||||||
|
|
||||||
|
8 56 57 58 59 60 61 62 63 8 -+
|
||||||
|
7 48 49 50 51 52 53 54 55 7 |- bf2
|
||||||
|
6 40 41 42 43 44 45 46 47 6 |
|
||||||
|
5 32 33 34 35 36 37 38 39 5 -+
|
||||||
|
4 24 25 26 27 28 29 30 31 4 -+
|
||||||
|
3 16 17 18 19 20 21 22 23 3 |
|
||||||
|
2 8 9 10 11 12 13 14 15 2 |- bf1
|
||||||
|
1 0 1 2 3 4 5 6 7 1 -+
|
||||||
|
|
||||||
|
a b c d e f g h
|
||||||
|
*/
|
||||||
|
|
||||||
|
use crate::piece::{PieceColor, PieceType};
|
||||||
|
|
||||||
|
type Boardfield = [u8; 32];
|
||||||
|
pub trait BoardfieldOps {
|
||||||
|
fn new() -> Self where Self: Sized;
|
||||||
|
fn startpos() -> Self where Self: Sized;
|
||||||
|
fn get_pos(&self, boardloc: usize) -> u8;
|
||||||
|
fn set_pos(&mut self, boardloc: usize, piece: u8);
|
||||||
|
}
|
||||||
|
impl BoardfieldOps for Boardfield {
|
||||||
|
fn new() -> Self where Self: Sized {
|
||||||
|
[0u8; 32]
|
||||||
|
}
|
||||||
|
|
||||||
|
fn startpos() -> Self where Self: Sized {
|
||||||
|
let mut field = Self::new();
|
||||||
|
|
||||||
|
// a1-h1 (RNBQKBNR)
|
||||||
|
field.set_pos(0, PieceColor::White as u8 | PieceType::Rook as u8);
|
||||||
|
field.set_pos(1, PieceColor::White as u8 | PieceType::Knight as u8);
|
||||||
|
field.set_pos(2, PieceColor::White as u8 | PieceType::Bishop as u8);
|
||||||
|
field.set_pos(3, PieceColor::White as u8 | PieceType::Queen as u8);
|
||||||
|
field.set_pos(4, PieceColor::White as u8 | PieceType::King as u8);
|
||||||
|
field.set_pos(5, PieceColor::White as u8 | PieceType::Bishop as u8);
|
||||||
|
field.set_pos(6, PieceColor::White as u8 | PieceType::Knight as u8);
|
||||||
|
field.set_pos(7, PieceColor::White as u8 | PieceType::Rook as u8);
|
||||||
|
|
||||||
|
// a2-h2 (PPPPPPPP)
|
||||||
|
field.set_pos(8, PieceColor::White as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(9, PieceColor::White as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(10, PieceColor::White as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(11, PieceColor::White as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(12, PieceColor::White as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(13, PieceColor::White as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(14, PieceColor::White as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(15, PieceColor::White as u8 | PieceType::Pawn as u8);
|
||||||
|
|
||||||
|
// a7-h7 (pppppppp)
|
||||||
|
field.set_pos(48, PieceColor::Black as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(49, PieceColor::Black as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(50, PieceColor::Black as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(51, PieceColor::Black as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(52, PieceColor::Black as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(53, PieceColor::Black as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(54, PieceColor::Black as u8 | PieceType::Pawn as u8);
|
||||||
|
field.set_pos(55, PieceColor::Black as u8 | PieceType::Pawn as u8);
|
||||||
|
|
||||||
|
// a8-h8 (RNBQKBNR)
|
||||||
|
field.set_pos(56, PieceColor::Black as u8 | PieceType::Rook as u8);
|
||||||
|
field.set_pos(57, PieceColor::Black as u8 | PieceType::Knight as u8);
|
||||||
|
field.set_pos(58, PieceColor::Black as u8 | PieceType::Bishop as u8);
|
||||||
|
field.set_pos(59, PieceColor::Black as u8 | PieceType::Queen as u8);
|
||||||
|
field.set_pos(60, PieceColor::Black as u8 | PieceType::King as u8);
|
||||||
|
field.set_pos(61, PieceColor::Black as u8 | PieceType::Bishop as u8);
|
||||||
|
field.set_pos(62, PieceColor::Black as u8 | PieceType::Knight as u8);
|
||||||
|
field.set_pos(63, PieceColor::Black as u8 | PieceType::Rook as u8);
|
||||||
|
|
||||||
|
|
||||||
|
field
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_pos(&self, boardloc: usize) -> u8 {
|
||||||
|
// bf1: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
|
||||||
|
// bf2: 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
|
||||||
|
|
||||||
|
if boardloc > 63 {
|
||||||
|
panic!("boardloc out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
let field = self[boardloc / 2];
|
||||||
|
let shift = 4 * (boardloc % 2);
|
||||||
|
|
||||||
|
(field & (0b1111 << shift)) >> shift
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_pos(&mut self, boardloc: usize, piece: u8) {
|
||||||
|
if boardloc > 63 {
|
||||||
|
panic!("boardloc out of range");
|
||||||
|
}
|
||||||
|
|
||||||
|
let field = self[boardloc / 2];
|
||||||
|
let shift = 4 * (boardloc % 2);
|
||||||
|
|
||||||
|
// clear out the field
|
||||||
|
let bf_cleared = field & !(0b1111 << shift);
|
||||||
|
// then shift over the actual piece data
|
||||||
|
let piece_shifted = piece << shift;
|
||||||
|
// then OR them together
|
||||||
|
let bf_new = bf_cleared | piece_shifted;
|
||||||
|
|
||||||
|
self[boardloc / 2] = bf_new;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use crate::board::{Boardfield, BoardfieldOps};
|
||||||
|
use crate::piece::{PieceColor, PieceType};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn bitfield_board() {
|
||||||
|
let field = Boardfield::startpos();
|
||||||
|
|
||||||
|
assert_eq!(field.get_pos(0), PieceType::Rook as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(1), PieceType::Knight as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(2), PieceType::Bishop as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(3), PieceType::Queen as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(4), PieceType::King as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(5), PieceType::Bishop as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(6), PieceType::Knight as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(7), PieceType::Rook as u8 | PieceColor::White as u8);
|
||||||
|
|
||||||
|
assert_eq!(field.get_pos(8), PieceType::Pawn as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(9), PieceType::Pawn as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(10), PieceType::Pawn as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(11), PieceType::Pawn as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(12), PieceType::Pawn as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(13), PieceType::Pawn as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(14), PieceType::Pawn as u8 | PieceColor::White as u8);
|
||||||
|
assert_eq!(field.get_pos(15), PieceType::Pawn as u8 | PieceColor::White as u8);
|
||||||
|
|
||||||
|
assert_eq!(field.get_pos(48), PieceType::Pawn as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(49), PieceType::Pawn as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(50), PieceType::Pawn as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(51), PieceType::Pawn as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(52), PieceType::Pawn as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(53), PieceType::Pawn as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(54), PieceType::Pawn as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(55), PieceType::Pawn as u8 | PieceColor::Black as u8);
|
||||||
|
|
||||||
|
assert_eq!(field.get_pos(56), PieceType::Rook as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(57), PieceType::Knight as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(58), PieceType::Bishop as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(59), PieceType::Queen as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(60), PieceType::King as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(61), PieceType::Bishop as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(62), PieceType::Knight as u8 | PieceColor::Black as u8);
|
||||||
|
assert_eq!(field.get_pos(63), PieceType::Rook as u8 | PieceColor::Black as u8);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,8 @@ use crate::uci::{uci_handle_command, UCIState};
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
|
|
||||||
pub mod uci;
|
pub mod uci;
|
||||||
|
pub mod board;
|
||||||
|
pub mod piece;
|
||||||
|
|
||||||
pub const ENGINE_NAME: &str = "Bamboo";
|
pub const ENGINE_NAME: &str = "Bamboo";
|
||||||
pub const ENGINE_VERSION: &str = "1.0";
|
pub const ENGINE_VERSION: &str = "1.0";
|
||||||
|
|
|
@ -0,0 +1,82 @@
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum PieceType {
|
||||||
|
Pawn = 1,
|
||||||
|
Knight = 2,
|
||||||
|
Bishop = 3,
|
||||||
|
Rook = 4,
|
||||||
|
Queen = 5,
|
||||||
|
King = 6
|
||||||
|
}
|
||||||
|
|
||||||
|
#[repr(u8)]
|
||||||
|
pub enum PieceColor {
|
||||||
|
White = 8,
|
||||||
|
Black = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
pub type Piece = u8;
|
||||||
|
pub trait PieceOps {
|
||||||
|
fn is_white(value: u8) -> bool;
|
||||||
|
|
||||||
|
fn is_black(value: u8) -> bool;
|
||||||
|
}
|
||||||
|
impl PieceOps for Piece {
|
||||||
|
fn is_white(value: u8) -> bool {
|
||||||
|
if value < 8 {
|
||||||
|
false
|
||||||
|
} else {
|
||||||
|
value & PieceColor::White as u8 != 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_black(value: u8) -> bool {
|
||||||
|
!Self::is_white(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod piece_tests {
|
||||||
|
use crate::piece::{Piece, PieceColor, PieceOps, PieceType};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn piece_serialization() {
|
||||||
|
assert_eq!(PieceType::Pawn as u8 | PieceColor::White as u8, 0b1001);
|
||||||
|
assert_eq!(PieceType::Pawn as u8 | PieceColor::Black as u8, 0b0001);
|
||||||
|
|
||||||
|
assert_eq!(PieceType::Knight as u8 | PieceColor::White as u8, 0b1010);
|
||||||
|
assert_eq!(PieceType::Knight as u8 | PieceColor::Black as u8, 0b0010);
|
||||||
|
|
||||||
|
assert_eq!(PieceType::Bishop as u8 | PieceColor::White as u8, 0b1011);
|
||||||
|
assert_eq!(PieceType::Bishop as u8 | PieceColor::Black as u8, 0b0011);
|
||||||
|
|
||||||
|
assert_eq!(PieceType::Rook as u8 | PieceColor::White as u8, 0b1100);
|
||||||
|
assert_eq!(PieceType::Rook as u8 | PieceColor::Black as u8, 0b0100);
|
||||||
|
|
||||||
|
assert_eq!(PieceType::Queen as u8 | PieceColor::White as u8, 0b1101);
|
||||||
|
assert_eq!(PieceType::Queen as u8 | PieceColor::Black as u8, 0b0101);
|
||||||
|
|
||||||
|
assert_eq!(PieceType::King as u8 | PieceColor::White as u8, 0b1110);
|
||||||
|
assert_eq!(PieceType::King as u8 | PieceColor::Black as u8, 0b0110);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn piece_color_checks() {
|
||||||
|
assert!(!Piece::is_white(PieceType::Pawn as u8 | PieceColor::Black as u8));
|
||||||
|
assert!(Piece::is_white(PieceType::Pawn as u8 | PieceColor::White as u8));
|
||||||
|
|
||||||
|
assert!(!Piece::is_white(PieceType::Knight as u8 | PieceColor::Black as u8));
|
||||||
|
assert!(Piece::is_white(PieceType::Knight as u8 | PieceColor::White as u8));
|
||||||
|
|
||||||
|
assert!(!Piece::is_white(PieceType::Bishop as u8 | PieceColor::Black as u8));
|
||||||
|
assert!(Piece::is_white(PieceType::Bishop as u8 | PieceColor::White as u8));
|
||||||
|
|
||||||
|
assert!(!Piece::is_white(PieceType::Rook as u8 | PieceColor::Black as u8));
|
||||||
|
assert!(Piece::is_white(PieceType::Rook as u8 | PieceColor::White as u8));
|
||||||
|
|
||||||
|
assert!(!Piece::is_white(PieceType::Queen as u8 | PieceColor::Black as u8));
|
||||||
|
assert!(Piece::is_white(PieceType::Queen as u8 | PieceColor::White as u8));
|
||||||
|
|
||||||
|
assert!(!Piece::is_white(PieceType::King as u8 | PieceColor::Black as u8));
|
||||||
|
assert!(Piece::is_white(PieceType::King as u8 | PieceColor::White as u8));
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,6 @@
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use crate::{ENGINE_AUTHOR, ENGINE_NAME, ENGINE_VERSION};
|
use crate::{ENGINE_AUTHOR, ENGINE_NAME, ENGINE_VERSION};
|
||||||
use std::fmt::Write;
|
use std::fmt::Write;
|
||||||
use std::fs;
|
|
||||||
use std::path::Path;
|
|
||||||
use std::sync::{Arc};
|
use std::sync::{Arc};
|
||||||
use spin::Mutex;
|
use spin::Mutex;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue