some work (prep for NN training)

This commit is contained in:
c0repwn3r 2023-02-13 11:51:25 -05:00
parent 0483f4ce86
commit 4e78de70d7
Signed by: core
GPG Key ID: FDBF740DADDCEECF
8 changed files with 153 additions and 8 deletions

View File

@ -1,5 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<module type="CPP_MODULE" version="4"> <module type="CPP_MODULE" version="4">
<component name="FacetManager">
<facet type="Python" name="Python facet">
<configuration sdkName="Python 3.10" />
</facet>
</component>
<component name="NewModuleRootManager"> <component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$"> <content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" /> <sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
@ -7,5 +12,6 @@
</content> </content>
<orderEntry type="inheritedJdk" /> <orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" /> <orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="Python 3.10 interpreter library" level="application" />
</component> </component>
</module> </module>

7
Cargo.lock generated
View File

@ -12,9 +12,16 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
name = "bamboo" name = "bamboo"
version = "0.1.0" version = "0.1.0"
dependencies = [ dependencies = [
"hex",
"spin", "spin",
] ]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]] [[package]]
name = "lock_api" name = "lock_api"
version = "0.4.9" version = "0.4.9"

View File

@ -6,4 +6,5 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
spin = "0.9.5" spin = "0.9.5"
hex = "0.4.3"

1
positions.csv Normal file
View File

@ -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
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

View File

@ -5,7 +5,7 @@ use crate::boardfield::{Boardfield, BoardfieldOps};
use crate::piece::{PieceColor, PieceOnBoard, PieceType}; use crate::piece::{PieceColor, PieceOnBoard, PieceType};
use crate::utils::{algebraic_to_boardloc, AlgebraicNotationError, boardloc_to_algebraic}; use crate::utils::{algebraic_to_boardloc, AlgebraicNotationError, boardloc_to_algebraic};
#[derive(Debug)] #[derive(Debug, PartialEq)]
pub struct Board { pub struct Board {
bitfield: Boardfield, 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. // 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 { 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<Self, FENParseError> { pub fn from_fen(fen: &str) -> Result<Self, FENParseError> {
let components = fen.split(' ').collect::<Vec<&str>>(); let components = fen.split(' ').collect::<Vec<&str>>();
if components.len() != 6 { if components.len() != 6 {
@ -115,7 +175,7 @@ impl Board {
file += num; file += num;
}, },
'/' => { '/' => {
if rank == 8 { if rank == 7 {
return Err(FENParseError::CannotSkipToOutsideOfBoard { got: 1, which_is: file + 1 }) 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<PieceOnBoard, FENParseError> { fn create_fen_piece(c: char, rank: usize, file: usize) -> Result<PieceOnBoard, FENParseError> {
println!("playing {} at {} ({}, {})", c, rank + file * 8, file, rank);
Ok(PieceOnBoard { Ok(PieceOnBoard {
loc: rank + file * 8, loc: rank + file * 8,
value: match c { value: match c {
@ -189,6 +248,41 @@ mod tests {
use crate::boardloc; use crate::boardloc;
use crate::piece::{PieceColor, PieceType}; 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] #[test]
pub fn fen_parse_testing() { pub fn fen_parse_testing() {
let board = Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").unwrap(); let board = Board::from_fen("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1").unwrap();

View File

@ -33,6 +33,7 @@ pub trait BoardfieldOps {
fn startpos() -> Self where Self: Sized; fn startpos() -> Self where Self: Sized;
fn get_pos(&self, boardloc: usize) -> u8; fn get_pos(&self, boardloc: usize) -> u8;
fn set_pos(&mut self, boardloc: usize, piece: u8); fn set_pos(&mut self, boardloc: usize, piece: u8);
fn get_field(&self) -> [u8; 32];
} }
impl BoardfieldOps for Boardfield { impl BoardfieldOps for Boardfield {
fn new() -> Self where Self: Sized { fn new() -> Self where Self: Sized {
@ -117,6 +118,12 @@ impl BoardfieldOps for Boardfield {
self[boardloc / 2] = bf_new; self[boardloc / 2] = bf_new;
} }
fn get_field(&self) -> [u8; 32] {
*self
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -3,6 +3,7 @@ use std::path::Path;
use std::sync::{Arc}; use std::sync::{Arc};
use crate::uci::{uci_handle_command, UCIState}; use crate::uci::{uci_handle_command, UCIState};
use spin::Mutex; use spin::Mutex;
use crate::board::Board;
#[cfg(not(tarpaulin_include))] // UCI parse engine is not tested with tarpaulin, outer test harness is planned #[cfg(not(tarpaulin_include))] // UCI parse engine is not tested with tarpaulin, outer test harness is planned
pub mod uci; pub mod uci;
@ -19,6 +20,29 @@ pub const ENGINE_AUTHOR: &str = "c0repwn3r";
#[cfg(not(tarpaulin_include))] #[cfg(not(tarpaulin_include))]
fn main() { fn main() {
if std::env::args().len() > 1 {
let args = std::env::args().collect::<Vec<String>>();
if args[1] == "--serBoard" && args.len() != 3 {
println!("usage: bamboo [--serBoard <fenString>]");
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 <fenString>]");
std::process::exit(1);
}
}
println!("{} {} by {}", ENGINE_NAME, ENGINE_VERSION, ENGINE_AUTHOR); println!("{} {} by {}", ENGINE_NAME, ENGINE_VERSION, ENGINE_AUTHOR);
let mut uci_state = UCIState::new(); let mut uci_state = UCIState::new();

View File

@ -1,4 +1,4 @@
#[derive(Debug)] #[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
pub struct PieceOnBoard { pub struct PieceOnBoard {
pub loc: usize, pub loc: usize,
pub value: Piece pub value: Piece
@ -12,7 +12,7 @@ impl PieceOnBoard {
} }
} }
#[derive(Debug)] #[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
#[repr(u8)] #[repr(u8)]
pub enum PieceType { pub enum PieceType {
Pawn = 1, Pawn = 1,
@ -23,7 +23,7 @@ pub enum PieceType {
King = 6 King = 6
} }
#[derive(Debug)] #[derive(Debug, Ord, PartialOrd, Eq, PartialEq)]
#[repr(u8)] #[repr(u8)]
pub enum PieceColor { pub enum PieceColor {
White = 8, White = 8,
@ -52,10 +52,15 @@ impl PieceOps for Piece {
#[cfg(test)] #[cfg(test)]
mod piece_tests { mod piece_tests {
use crate::piece::{Piece, PieceColor, PieceOps, PieceType}; use crate::piece::{Piece, PieceColor, PieceOnBoard, PieceOps, PieceType};
#[test] #[test]
fn piece_serialization() { 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::White as u8, 0b1001);
assert_eq!(PieceType::Pawn as u8 | PieceColor::Black as u8, 0b0001); assert_eq!(PieceType::Pawn as u8 | PieceColor::Black as u8, 0b0001);