diff --git a/.idea/bamboo.iml b/.idea/bamboo.iml
index c254557..394aa25 100644
--- a/.idea/bamboo.iml
+++ b/.idea/bamboo.iml
@@ -1,5 +1,10 @@
+
+
+
+
+
@@ -7,5 +12,6 @@
+
\ No newline at end of file
diff --git a/Cargo.lock b/Cargo.lock
index c2fea0b..4a7ce5f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -12,9 +12,16 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
name = "bamboo"
version = "0.1.0"
dependencies = [
+ "hex",
"spin",
]
+[[package]]
+name = "hex"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
+
[[package]]
name = "lock_api"
version = "0.4.9"
diff --git a/Cargo.toml b/Cargo.toml
index 01f81eb..97cd20b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -6,4 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
-spin = "0.9.5"
\ No newline at end of file
+spin = "0.9.5"
+hex = "0.4.3"
\ No newline at end of file
diff --git a/positions.csv b/positions.csv
new file mode 100644
index 0000000..63090d4
--- /dev/null
+++ b/positions.csv
@@ -0,0 +1 @@
+1,1,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,1,1,1,0,1,1,0,1,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,1,1,1,0,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,1,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,1,0,0,1,0,0,0,1,1,0,0,0,0,0,1,1,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,1,0,0,1,0,1,0,1,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,-,0,-2801
\ No newline at end of file
diff --git a/src/board.rs b/src/board.rs
index 1b2a2ae..08cf0d0 100644
--- a/src/board.rs
+++ b/src/board.rs
@@ -5,7 +5,7 @@ use crate::boardfield::{Boardfield, BoardfieldOps};
use crate::piece::{PieceColor, PieceOnBoard, PieceType};
use crate::utils::{algebraic_to_boardloc, AlgebraicNotationError, boardloc_to_algebraic};
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
pub struct Board {
bitfield: Boardfield,
// While this is a less efficient memory layout, having an array of where all the pieces are will make move generation significantly faster.
@@ -48,6 +48,66 @@ impl Display for FENParseError {
}
impl Board {
+ pub fn to_board_id(&self) -> [u8; 41] {
+ // 0-31 BOARDFILED
+ // 32 FLAGS
+ // 33-36 EN_PASSANT_TARGET
+ // 37-38 HALFMOVE_COUNTER
+ // 39-40 FULLMOVE_COUNTER
+
+ let mut res = [0u8; 41];
+
+ res[0..32].copy_from_slice(&self.bitfield.get_field());
+
+ let mut flags_byte = res[32];
+ // FLAGS BYTE:
+ //
+ // / unused
+ // |
+ // 000 0 0 0 0 0
+ // | | | | \
+ // | | | | turn to move (1 white, 0 black)
+ // | | | \
+ // | | | white kingside castling
+ // | | \
+ // | | white queenside castling
+ // | \
+ // | black kingside castling
+ // \
+ // black queenside castling
+ if self.turn == PieceColor::White {
+ flags_byte |= 0b1;
+ }
+ if self.castle_white_kingside {
+ flags_byte |= 0b1 << 1;
+ }
+ if self.castle_white_queenside {
+ flags_byte |= 0b1 << 2;
+ }
+ if self.castle_black_kingside {
+ flags_byte |= 0b1 << 3;
+ }
+ if self.castle_black_queenside {
+ flags_byte |= 0b1 << 4;
+ }
+ res[32] = flags_byte;
+
+ let en_passant_target: [u8; 4] = match self.en_passant_target {
+ Some(target) => {
+ (target as u32).to_le_bytes()
+ },
+ None => {
+ u32::MAX.to_le_bytes()
+ }
+ };
+ res[33..37].copy_from_slice(&en_passant_target);
+
+ res[37..39].copy_from_slice(&(self.halfmove_counter as u16).to_le_bytes());
+ res[39..41].copy_from_slice(&(self.move_counter as u16).to_le_bytes());
+
+ res
+ }
+
pub fn from_fen(fen: &str) -> Result {
let components = fen.split(' ').collect::>();
if components.len() != 6 {
@@ -115,7 +175,7 @@ impl Board {
file += num;
},
'/' => {
- if rank == 8 {
+ if rank == 7 {
return Err(FENParseError::CannotSkipToOutsideOfBoard { got: 1, which_is: file + 1 })
}
@@ -142,7 +202,6 @@ impl Board {
}
fn create_fen_piece(c: char, rank: usize, file: usize) -> Result {
- println!("playing {} at {} ({}, {})", c, rank + file * 8, file, rank);
Ok(PieceOnBoard {
loc: rank + file * 8,
value: match c {
@@ -189,6 +248,41 @@ mod tests {
use crate::boardloc;
use crate::piece::{PieceColor, PieceType};
+ #[test]
+ pub fn test_serialization() {
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w - - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 1, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w q - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 17, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w k - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 9, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w kq - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 25, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w Q - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 5, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w Qq - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 21, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w Qk - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 13, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w Qkq - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 29, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w K - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 3, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w Kq - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 19, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w Kk - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 11, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQ - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 7, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQq - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 23, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQk - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 15, 255, 255, 255, 255, 0, 0, 1, 0]);
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 31, 255, 255, 255, 255, 0, 0, 1, 0]);
+
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR b KQkq a4 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 30, 3, 0, 0, 0, 0, 0, 1, 0]);
+
+ assert!(Board::from_fen("d").is_err());
+ assert!(Board::from_fen("8/8/8/8/8/8/8/8 h - - 0 1").is_err());
+ assert!(Board::from_fen("8/8/8/8/8/8/8 w KQkq j4 0 1").is_err());
+
+ assert!(Board::from_fen("9/8/8/8/8/8/8 w KQkq a4 0 1").is_err());
+ assert!(Board::from_fen("18/8/8/8/8/8/8 w KQkq a4 0 1").is_err());
+ assert!(Board::from_fen("8/8/8/8/8/8/8/8/8 w KQkq a4 0 1").is_err());
+ assert!(Board::from_fen("8/8/8/8/8/8/8/8 w KQkq a4 a 1").is_err());
+ assert!(Board::from_fen("8/8/8/8/8/8/8/8 w KQkq a4 0 a").is_err());
+
+ assert!(Board::from_fen("s w KQkq a4 0 1").is_err());
+
+ assert_eq!(Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").unwrap().to_board_id(), [156, 0, 0, 65, 154, 0, 0, 33, 155, 0, 0, 49, 157, 0, 0, 81, 158, 0, 0, 97, 155, 0, 0, 49, 154, 0, 0, 33, 156, 0, 0, 65, 31, 255, 255, 255, 255, 0, 0, 1, 0]);
+ }
+
#[test]
pub fn fen_parse_testing() {
let board = Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").unwrap();
diff --git a/src/boardfield.rs b/src/boardfield.rs
index 0e54935..3fd601f 100644
--- a/src/boardfield.rs
+++ b/src/boardfield.rs
@@ -33,6 +33,7 @@ pub trait BoardfieldOps {
fn startpos() -> Self where Self: Sized;
fn get_pos(&self, boardloc: usize) -> u8;
fn set_pos(&mut self, boardloc: usize, piece: u8);
+ fn get_field(&self) -> [u8; 32];
}
impl BoardfieldOps for Boardfield {
fn new() -> Self where Self: Sized {
@@ -117,6 +118,12 @@ impl BoardfieldOps for Boardfield {
self[boardloc / 2] = bf_new;
}
+
+ fn get_field(&self) -> [u8; 32] {
+ *self
+ }
+
+
}
#[cfg(test)]
diff --git a/src/main.rs b/src/main.rs
index 4ba4aa8..b6f9293 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -3,6 +3,7 @@ use std::path::Path;
use std::sync::{Arc};
use crate::uci::{uci_handle_command, UCIState};
use spin::Mutex;
+use crate::board::Board;
#[cfg(not(tarpaulin_include))] // UCI parse engine is not tested with tarpaulin, outer test harness is planned
pub mod uci;
@@ -19,6 +20,29 @@ pub const ENGINE_AUTHOR: &str = "c0repwn3r";
#[cfg(not(tarpaulin_include))]
fn main() {
+ if std::env::args().len() > 1 {
+ let args = std::env::args().collect::>();
+
+ if args[1] == "--serBoard" && args.len() != 3 {
+ println!("usage: bamboo [--serBoard ]");
+ std::process::exit(1);
+ } else if args[1] == "--serBoard" {
+ match Board::from_fen(args[2].as_str()) {
+ Ok(b) => {
+ println!("{}", hex::encode(b.to_board_id()));
+ std::process::exit(0);
+ },
+ Err(e) => {
+ println!("Error decoding FEN string: {}", e);
+ std::process::exit(1);
+ }
+ }
+ } else {
+ println!("usage: bamboo [--serBoard ]");
+ std::process::exit(1);
+ }
+ }
+
println!("{} {} by {}", ENGINE_NAME, ENGINE_VERSION, ENGINE_AUTHOR);
let mut uci_state = UCIState::new();
diff --git a/src/piece.rs b/src/piece.rs
index 2e872e5..0514069 100644
--- a/src/piece.rs
+++ b/src/piece.rs
@@ -1,4 +1,4 @@
-#[derive(Debug)]
+#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
pub struct PieceOnBoard {
pub loc: usize,
pub value: Piece
@@ -12,7 +12,7 @@ impl PieceOnBoard {
}
}
-#[derive(Debug)]
+#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
#[repr(u8)]
pub enum PieceType {
Pawn = 1,
@@ -23,7 +23,7 @@ pub enum PieceType {
King = 6
}
-#[derive(Debug)]
+#[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
#[repr(u8)]
pub enum PieceColor {
White = 8,
@@ -52,10 +52,15 @@ impl PieceOps for Piece {
#[cfg(test)]
mod piece_tests {
- use crate::piece::{Piece, PieceColor, PieceOps, PieceType};
+ use crate::piece::{Piece, PieceColor, PieceOnBoard, PieceOps, PieceType};
#[test]
fn piece_serialization() {
+ assert_eq!(PieceOnBoard::new(0, 0), PieceOnBoard {
+ loc: 0,
+ value: 0,
+ });
+
assert_eq!(PieceType::Pawn as u8 | PieceColor::White as u8, 0b1001);
assert_eq!(PieceType::Pawn as u8 | PieceColor::Black as u8, 0b0001);