use crate::bitboard::Bitboard; #[derive(Debug)] pub struct Board { pub pieces: [Bitboard; 12], } pub enum PieceTypes { Pawn, PawnBlack, Knight, KnightBlack, Bishop, BishopBlack, Rook, RookBlack, Queen, QueenBlack, King, KingBlack, } const PIECE_CHARS: [&str; 12] = [ "♟︎", "♙", "♞", "♘", "♝", "♗", "♜", "♖", "♛", "♕", "♚", "♔", ]; impl Board { #[allow(non_snake_case)] pub fn from_FEN(fen: String) -> Self { let mut pieces = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; let mut rank = 7; let mut file = 0i32; for character in fen.chars() { let index = rank * 8 + file; let position = 1 << index.clamp(0, 63); if character.is_numeric() { let digit = match character.to_digit(10) { None => todo!("What to do here?"), Some(digit) => digit, }; if digit > 0 && digit <= 8 { file += digit as i32; } } else { match character { 'P' => pieces[PieceTypes::Pawn as usize] |= position, 'N' => pieces[PieceTypes::Knight as usize] |= position, 'B' => pieces[PieceTypes::Bishop as usize] |= position, 'R' => pieces[PieceTypes::Rook as usize] |= position, 'Q' => pieces[PieceTypes::Queen as usize] |= position, 'K' => pieces[PieceTypes::King as usize] |= position, 'p' => pieces[PieceTypes::PawnBlack as usize] |= position, 'n' => pieces[PieceTypes::KnightBlack as usize] |= position, 'b' => pieces[PieceTypes::BishopBlack as usize] |= position, 'r' => pieces[PieceTypes::RookBlack as usize] |= position, 'q' => pieces[PieceTypes::QueenBlack as usize] |= position, 'k' => pieces[PieceTypes::KingBlack as usize] |= position, '/' => { rank -= 1; file = -1; // So it becomes 0 }, ' ' => { break }, // TODO: break for now, parse everything else later '-' => {}, // TODO 'w' => {}, // TODO _ => todo!("Unexpected character!"), } file += 1; } } Self { pieces } } pub fn print(&self) { println!(); for rank in (0..8).rev() { print!("{}|", rank + 1); for file in 0..8 { let index = rank * 8 + file; let position: Bitboard = 1 << index; let mut found = false; for (piec_type, piece_bitboard) in self.pieces.iter().enumerate() { if (piece_bitboard & position) > 0 { found = true; print!("{} ", PIECE_CHARS[piec_type]); } } if !found { print!(". "); } } println!(); } println!(" a b c d e f g h"); } } pub enum Color { White, Black, } /// Aliases to board square indexes #[allow(dead_code)] pub enum Square { A1, B1, C1, D1, E1, F1, G1, H1, A2, B2, C2, D2, E2, F2, G2, H2, A3, B3, C3, D3, E3, F3, G3, H3, A4, B4, C4, D4, E4, F4, G4, H4, A5, B5, C5, D5, E5, F5, G5, H5, A6, B6, C6, D6, E6, F6, G6, H6, A7, B7, C7, D7, E7, F7, G7, H7, A8, B8, C8, D8, E8, F8, G8, H8, } #[cfg(test)] mod tests { use super::*; use crate::bitboard; #[test] fn test_square_enum() { assert_eq!(Square::A1 as u8, 0); assert_eq!(Square::F1 as u8, 5); assert_eq!(Square::H8 as u8, 63); } #[test] fn test_from_fen() { let fen = String::from("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR w KQkq - 0 1"); let board = Board::from_FEN(fen); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::Pawn as usize]), 8); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::Knight as usize]), 2); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::Bishop as usize]), 2); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::Rook as usize]), 2); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::Queen as usize]), 1); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::King as usize]), 1); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::PawnBlack as usize]), 8); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::KnightBlack as usize]), 2); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::BishopBlack as usize]), 2); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::RookBlack as usize]), 2); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::QueenBlack as usize]), 1); assert_eq!(bitboard::pop_count(board.pieces[PieceTypes::KingBlack as usize]), 1); assert_eq!(bitboard::bitscan(board.pieces[PieceTypes::King as usize]), Square::E1 as u8); assert_eq!(bitboard::bitscan(board.pieces[PieceTypes::QueenBlack as usize]), Square::D8 as u8); board.print(); } }