diff --git a/Cargo.lock b/Cargo.lock index 553a44f..91b004d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,48 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "bitvec" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + [[package]] name = "chessbot" version = "0.1.0" +dependencies = [ + "bitvec", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] diff --git a/Cargo.toml b/Cargo.toml index 7d86fef..f663e22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,3 +4,4 @@ version = "0.1.0" edition = "2024" [dependencies] +bitvec = "1.0.1" diff --git a/src/lib.rs b/src/lib.rs index 74e7e64..6e8ddb7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ +use bitvec::prelude::*; #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Piece { Pawn, @@ -31,74 +32,118 @@ impl Piece { } } -#[derive(Debug, Clone, Copy, PartialEq, Eq)] -struct LocatedPiece { - piece: Piece, - rank: usize, - file: usize, +#[derive(Clone, Copy, PartialEq, Eq, Default)] +struct BitBoard { + backing: u64, +} +impl BitBoard { + fn get_square(&self, file: u8, rank: u8) -> bool { + self.backing & (rank * 8 + file) as u64 != 0 + } + fn set_square(&mut self, file: u8, rank: u8) { + self.backing &= (rank * 8 + file) as u64 + } + fn del_square(&mut self, file: u8, rank: u8) { + self.backing &= !((rank * 8 + file) as u64) + } + fn toggle_square(&mut self, file: u8, rank: u8) { + self.backing ^= (rank * 8 + file) as u64 + } + fn value(&self) -> u32 { + self.backing.count_ones() + } +} + +struct Move { + source_rank: u8, + dest_rank: u8, + source_file: u8, + dest_file: u8, } pub struct Board { - white: Vec, - black: Vec, white_to_move: bool, + white_pawns: BitBoard, + white_knights: BitBoard, + white_bishops: BitBoard, + white_rooks: BitBoard, + white_queens: BitBoard, + white_king: BitBoard, + black_pawns: BitBoard, + black_knights: BitBoard, + black_bishops: BitBoard, + black_rooks: BitBoard, + black_queens: BitBoard, + black_king: BitBoard, } impl Board { pub fn new() -> Self { - let white_pawns = (0..8) - .map(|file| LocatedPiece { - piece: Piece::Pawn, - rank: 1, - file, - }) - .collect::>(); - let black_pawns = white_pawns - .iter() - .map(|&lp| LocatedPiece { rank: 6, ..lp }) - .collect::>(); - - let white_pieces = vec![ - Piece::Rook, - Piece::Knight, - Piece::Bishop, - Piece::Queen, - Piece::King, - Piece::Bishop, - Piece::Knight, - Piece::Rook, - ] - .into_iter() - .enumerate() - .map(|(idx, piece)| LocatedPiece { - piece, - rank: 0, - file: idx, - }); - - let black_pieces = white_pieces - .clone() - .rev() - .map(|lp| LocatedPiece { rank: 7, ..lp }); - + let white_pawns = BitBoard { + backing: 0xff << 1 * 8, + }; + let black_pawns = BitBoard { + backing: 0xff << 6 * 8, + }; + let white_knights = BitBoard { + backing: 0b01000010, + }; + let black_knights = BitBoard { + backing: 0b01000010 << 7 * 8, + }; + let white_bishops = BitBoard { + backing: 0b00100100, + }; + let black_bishops = BitBoard { + backing: 0b00100100 << 7 * 8, + }; + let white_rooks = BitBoard { + backing: 0b10000001, + }; + let black_rooks = BitBoard { + backing: 0b10000001 << 7 * 8, + }; + let white_queens = BitBoard { + backing: 0b00001000, + }; + let black_queens = BitBoard { + backing: 0b00001000 << 7 * 8, + }; + let white_king = BitBoard { + backing: 0b00010000, + }; + let black_king = BitBoard { + backing: 0b00010000 << 7 * 8, + }; Self { - white: white_pieces.chain(white_pawns).collect(), - black: black_pieces.chain(black_pawns).collect(), white_to_move: true, + white_pawns, + white_knights, + white_bishops, + white_rooks, + white_queens, + white_king, + + black_pawns, + black_knights, + black_bishops, + black_rooks, + black_queens, + black_king, } } fn material(&self) -> i32 { - let white_value = self - .white - .iter() - .map(|piece| piece.piece.value()) - .sum::(); - let black_value = self - .black - .iter() - .map(|piece| piece.piece.value()) - .sum::(); - white_value - black_value + let white_value = self.white_pawns.value() + + self.white_knights.value() * 3 + + self.white_bishops.value() * 3 + + self.white_rooks.value() * 5 + + self.white_queens.value() * 9; + let black_value = self.black_pawns.value() + + self.black_knights.value() * 3 + + self.black_bishops.value() * 3 + + self.black_rooks.value() * 5 + + self.black_queens.value() * 9; + white_value as i32 - black_value as i32 } pub fn make_move(&mut self, algebra: &str) { let (mover, non_mover) = self.movers_or_not(); @@ -170,7 +215,10 @@ impl Board { source_rank.is_none_or(|rank| rank == lp.rank) && source_file.is_none_or(|file| file == lp.file) }) - .find(|lp| self.valid_moves(lp.clone()).contains(&(dest_file, dest_rank))) + .find(|lp| { + self.valid_moves(lp.clone()) + .contains(&(dest_file, dest_rank)) + }) .unwrap(); self.capture_if_possible(dest_file, dest_rank); @@ -180,7 +228,7 @@ impl Board { fn valid_moves(&self, lp: &LocatedPiece) -> Vec<(usize, usize)> { let mut moves = vec![]; match lp.piece { - Piece::Pawn => ,//todo: en passant (requires a list of moves to keep track of whether the previous + Piece::Pawn => todo!(), //todo: en passant (requires a list of moves to keep track of whether the previous //move was one that is en passantable?) Piece::Knight => todo!(), Piece::Bishop => todo!(),