cleanroom implementation of a chess engine. doesn't work :)

change to bitboard repr, convert some functions

+148 -57
+42
Cargo.lock
··· 3 3 version = 4 4 4 5 5 [[package]] 6 + name = "bitvec" 7 + version = "1.0.1" 8 + source = "registry+https://github.com/rust-lang/crates.io-index" 9 + checksum = "1bc2832c24239b0141d5674bb9174f9d68a8b5b3f2753311927c172ca46f7e9c" 10 + dependencies = [ 11 + "funty", 12 + "radium", 13 + "tap", 14 + "wyz", 15 + ] 16 + 17 + [[package]] 6 18 name = "chessbot" 7 19 version = "0.1.0" 20 + dependencies = [ 21 + "bitvec", 22 + ] 23 + 24 + [[package]] 25 + name = "funty" 26 + version = "2.0.0" 27 + source = "registry+https://github.com/rust-lang/crates.io-index" 28 + checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" 29 + 30 + [[package]] 31 + name = "radium" 32 + version = "0.7.0" 33 + source = "registry+https://github.com/rust-lang/crates.io-index" 34 + checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" 35 + 36 + [[package]] 37 + name = "tap" 38 + version = "1.0.1" 39 + source = "registry+https://github.com/rust-lang/crates.io-index" 40 + checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" 41 + 42 + [[package]] 43 + name = "wyz" 44 + version = "0.5.1" 45 + source = "registry+https://github.com/rust-lang/crates.io-index" 46 + checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" 47 + dependencies = [ 48 + "tap", 49 + ]
+1
Cargo.toml
··· 4 4 edition = "2024" 5 5 6 6 [dependencies] 7 + bitvec = "1.0.1"
+105 -57
src/lib.rs
··· 1 + use bitvec::prelude::*; 1 2 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 2 3 enum Piece { 3 4 Pawn, ··· 31 32 } 32 33 } 33 34 34 - #[derive(Debug, Clone, Copy, PartialEq, Eq)] 35 - struct LocatedPiece { 36 - piece: Piece, 37 - rank: usize, 38 - file: usize, 35 + #[derive(Clone, Copy, PartialEq, Eq, Default)] 36 + struct BitBoard { 37 + backing: u64, 38 + } 39 + impl BitBoard { 40 + fn get_square(&self, file: u8, rank: u8) -> bool { 41 + self.backing & (rank * 8 + file) as u64 != 0 42 + } 43 + fn set_square(&mut self, file: u8, rank: u8) { 44 + self.backing &= (rank * 8 + file) as u64 45 + } 46 + fn del_square(&mut self, file: u8, rank: u8) { 47 + self.backing &= !((rank * 8 + file) as u64) 48 + } 49 + fn toggle_square(&mut self, file: u8, rank: u8) { 50 + self.backing ^= (rank * 8 + file) as u64 51 + } 52 + fn value(&self) -> u32 { 53 + self.backing.count_ones() 54 + } 55 + } 56 + 57 + struct Move { 58 + source_rank: u8, 59 + dest_rank: u8, 60 + source_file: u8, 61 + dest_file: u8, 39 62 } 40 63 41 64 pub struct Board { 42 - white: Vec<LocatedPiece>, 43 - black: Vec<LocatedPiece>, 44 65 white_to_move: bool, 66 + white_pawns: BitBoard, 67 + white_knights: BitBoard, 68 + white_bishops: BitBoard, 69 + white_rooks: BitBoard, 70 + white_queens: BitBoard, 71 + white_king: BitBoard, 72 + black_pawns: BitBoard, 73 + black_knights: BitBoard, 74 + black_bishops: BitBoard, 75 + black_rooks: BitBoard, 76 + black_queens: BitBoard, 77 + black_king: BitBoard, 45 78 } 46 79 47 80 impl Board { 48 81 pub fn new() -> Self { 49 - let white_pawns = (0..8) 50 - .map(|file| LocatedPiece { 51 - piece: Piece::Pawn, 52 - rank: 1, 53 - file, 54 - }) 55 - .collect::<Vec<_>>(); 56 - let black_pawns = white_pawns 57 - .iter() 58 - .map(|&lp| LocatedPiece { rank: 6, ..lp }) 59 - .collect::<Vec<_>>(); 60 - 61 - let white_pieces = vec![ 62 - Piece::Rook, 63 - Piece::Knight, 64 - Piece::Bishop, 65 - Piece::Queen, 66 - Piece::King, 67 - Piece::Bishop, 68 - Piece::Knight, 69 - Piece::Rook, 70 - ] 71 - .into_iter() 72 - .enumerate() 73 - .map(|(idx, piece)| LocatedPiece { 74 - piece, 75 - rank: 0, 76 - file: idx, 77 - }); 78 - 79 - let black_pieces = white_pieces 80 - .clone() 81 - .rev() 82 - .map(|lp| LocatedPiece { rank: 7, ..lp }); 83 - 82 + let white_pawns = BitBoard { 83 + backing: 0xff << 1 * 8, 84 + }; 85 + let black_pawns = BitBoard { 86 + backing: 0xff << 6 * 8, 87 + }; 88 + let white_knights = BitBoard { 89 + backing: 0b01000010, 90 + }; 91 + let black_knights = BitBoard { 92 + backing: 0b01000010 << 7 * 8, 93 + }; 94 + let white_bishops = BitBoard { 95 + backing: 0b00100100, 96 + }; 97 + let black_bishops = BitBoard { 98 + backing: 0b00100100 << 7 * 8, 99 + }; 100 + let white_rooks = BitBoard { 101 + backing: 0b10000001, 102 + }; 103 + let black_rooks = BitBoard { 104 + backing: 0b10000001 << 7 * 8, 105 + }; 106 + let white_queens = BitBoard { 107 + backing: 0b00001000, 108 + }; 109 + let black_queens = BitBoard { 110 + backing: 0b00001000 << 7 * 8, 111 + }; 112 + let white_king = BitBoard { 113 + backing: 0b00010000, 114 + }; 115 + let black_king = BitBoard { 116 + backing: 0b00010000 << 7 * 8, 117 + }; 84 118 Self { 85 - white: white_pieces.chain(white_pawns).collect(), 86 - black: black_pieces.chain(black_pawns).collect(), 87 119 white_to_move: true, 120 + white_pawns, 121 + white_knights, 122 + white_bishops, 123 + white_rooks, 124 + white_queens, 125 + white_king, 126 + 127 + black_pawns, 128 + black_knights, 129 + black_bishops, 130 + black_rooks, 131 + black_queens, 132 + black_king, 88 133 } 89 134 } 90 135 fn material(&self) -> i32 { 91 - let white_value = self 92 - .white 93 - .iter() 94 - .map(|piece| piece.piece.value()) 95 - .sum::<i32>(); 96 - let black_value = self 97 - .black 98 - .iter() 99 - .map(|piece| piece.piece.value()) 100 - .sum::<i32>(); 101 - white_value - black_value 136 + let white_value = self.white_pawns.value() 137 + + self.white_knights.value() * 3 138 + + self.white_bishops.value() * 3 139 + + self.white_rooks.value() * 5 140 + + self.white_queens.value() * 9; 141 + let black_value = self.black_pawns.value() 142 + + self.black_knights.value() * 3 143 + + self.black_bishops.value() * 3 144 + + self.black_rooks.value() * 5 145 + + self.black_queens.value() * 9; 146 + white_value as i32 - black_value as i32 102 147 } 103 148 pub fn make_move(&mut self, algebra: &str) { 104 149 let (mover, non_mover) = self.movers_or_not(); ··· 170 215 source_rank.is_none_or(|rank| rank == lp.rank) 171 216 && source_file.is_none_or(|file| file == lp.file) 172 217 }) 173 - .find(|lp| self.valid_moves(lp.clone()).contains(&(dest_file, dest_rank))) 218 + .find(|lp| { 219 + self.valid_moves(lp.clone()) 220 + .contains(&(dest_file, dest_rank)) 221 + }) 174 222 .unwrap(); 175 223 176 224 self.capture_if_possible(dest_file, dest_rank); ··· 180 228 fn valid_moves(&self, lp: &LocatedPiece) -> Vec<(usize, usize)> { 181 229 let mut moves = vec![]; 182 230 match lp.piece { 183 - Piece::Pawn => ,//todo: en passant (requires a list of moves to keep track of whether the previous 231 + Piece::Pawn => todo!(), //todo: en passant (requires a list of moves to keep track of whether the previous 184 232 //move was one that is en passantable?) 185 233 Piece::Knight => todo!(), 186 234 Piece::Bishop => todo!(),