Add ID for a board

This commit is contained in:
cool-mist 2025-01-26 18:51:18 +05:30
parent 32ec8107ab
commit 61b71eb8f0
5 changed files with 133 additions and 42 deletions

View File

@ -5,7 +5,11 @@ use std::{
};
use super::{
cmove::CMove, constants::BOARD_SIZE, piece::Piece, square::{Square, SquarePair}
cmove::CMove,
constants::BOARD_SIZE,
errors::SError,
piece::Piece,
square::{Square, SquarePair},
};
#[derive(Clone)]
@ -34,6 +38,51 @@ impl Board {
}
}
pub(crate) fn from_id(board_id: u128) -> Result<Self, SError> {
let mut board = Board::new();
let mut working = board_id;
for i in (0..BOARD_SIZE).rev() {
for j in (0..BOARD_SIZE).rev() {
let mask = 0b111;
let piece = Board::get_piece_from_encoding((working & mask) as u8);
working = working >> 3;
let piece = piece?;
board.set(Square::new(i, j, piece));
}
}
Ok(board)
}
pub(crate) fn from_string(board_string: String) -> Result<Self, SError> {
if board_string.chars().count() != 16 {
return Err(SError::InvalidBoard);
}
let mut board = Board::new();
let mut file = 0;
let mut rank = 0;
let mut chars = board_string.chars();
for r in 0..BOARD_SIZE {
for f in 0..BOARD_SIZE {
let c = chars.next().unwrap();
let piece = match c {
'K' => Piece::King,
'Q' => Piece::Queen,
'B' => Piece::Bishop,
'N' => Piece::Knight,
'R' => Piece::Rook,
'P' => Piece::Pawn,
'.' => continue,
_ => return Err(SError::InvalidBoard),
};
let square = Square::new(f, r, Some(piece));
board.set(square);
}
}
Ok(board)
}
pub(crate) fn set(&mut self, square: Square) -> Option<Piece> {
let new_is_occuppied = square.piece.is_some();
let existing = mem::replace(&mut self.cells[square.file][square.rank], square.piece);
@ -84,6 +133,21 @@ impl Board {
pub(crate) fn pretty_print(&self) {
println!("{}", self.print(true));
println!("{:^40}\n", format!("id: {}", self.id()));
}
pub(crate) fn id(&self) -> u128 {
let mut res: u128 = 0;
for i in 0..BOARD_SIZE {
for j in 0..BOARD_SIZE {
res = res << 3;
let byte = Board::get_piece_encoding(self.cells[i][j]);
res = res | byte as u128
}
}
res
}
fn print(&self, pretty: bool) -> String {
@ -239,40 +303,37 @@ impl Board {
ret
}
pub(crate) fn from_string(board_string: String) -> Option<Board> {
if board_string.chars().count() != 16 {
return None;
}
let mut board = Board::new();
let mut file = 0;
let mut rank = 0;
let mut chars = board_string.chars();
for r in 0..BOARD_SIZE {
for f in 0..BOARD_SIZE {
let c = chars.next().unwrap();
let piece = match c {
'K' => Piece::King,
'Q' => Piece::Queen,
'B' => Piece::Bishop,
'N' => Piece::Knight,
'R' => Piece::Rook,
'P' => Piece::Pawn,
'.' => continue,
_ => return None,
};
let square = Square::new(f, r, Some(piece));
board.set(square);
}
}
Some(board)
}
fn board_state_changed(&mut self) {
self.calc_legal_moves();
self.calc_game_state();
}
fn get_piece_encoding(piece: Option<Piece>) -> u8 {
match piece {
Some(p) => match p {
Piece::King => 0b001,
Piece::Queen => 0b010,
Piece::Rook => 0b011,
Piece::Bishop => 0b100,
Piece::Knight => 0b101,
Piece::Pawn => 0b110,
},
None => 0b000,
}
}
fn get_piece_from_encoding(encoding: u8) -> Result<Option<Piece>, SError> {
match encoding {
0b001 => Ok(Some(Piece::King)),
0b010 => Ok(Some(Piece::Queen)),
0b011 => Ok(Some(Piece::Rook)),
0b100 => Ok(Some(Piece::Bishop)),
0b101 => Ok(Some(Piece::Knight)),
0b110 => Ok(Some(Piece::Pawn)),
0b000 => Ok(None),
_ => Err(SError::InvalidBoard),
}
}
}
fn get_square_for_display(piece: &Option<Piece>, pretty: bool) -> String {
@ -490,4 +551,21 @@ mod tests {
assert_eq!(1, board.pieces_remaining);
assert_eq!(GameState::Won, board.game_state);
}
#[test]
fn test_encoding() {
let mut board = Board::new();
board.set(sq!("Pa1"));
board.set(sq!("Ra2"));
board.set(sq!("Qb2"));
board.set(sq!("Kd2"));
board.set(sq!("Bd4"));
board.set(sq!("Nc4"));
let id = board.id();
let board2 = Board::from_id(id);
let board2 = board2.unwrap();
validate_board!(board2, "..NB", "....", "RQ.K", "P...");
}
}

4
src/engine/errors.rs Normal file
View File

@ -0,0 +1,4 @@
#[derive(Debug)]
pub(crate) enum SError {
InvalidBoard,
}

View File

@ -1,4 +1,5 @@
pub(crate) mod constants;
pub(crate) mod errors;
pub(crate) mod board;
pub(crate) mod square;
pub(crate) mod cmove;

View File

@ -13,12 +13,11 @@ pub(crate) fn generate(num_pieces: u32, num_solutions: u32) -> GenerateStats {
Piece::Pawn,
Piece::Pawn,
Piece::Pawn,
Piece::Rook,
Piece::Pawn,
Piece::Bishop,
Piece::Bishop,
Piece::Knight,
Piece::Knight,
Piece::King,
Piece::Queen,
];
if num_pieces > candidate_pieces.len().try_into().unwrap() {

View File

@ -25,16 +25,21 @@ fn main() {
if args.print {
solve_puzzle(board);
}
} else if let Some(board_string) = args.solve {
let board = Board::from_string(board_string);
let Some(board) = board else {
println!("Invalid board string");
} else {
let board = if let Some(board_string) = args.solve_board {
Board::from_string(board_string)
} else if let Some(board_id) = args.solve {
Board::from_id(board_id)
} else {
println!("Use --help to see available options");
return;
};
let Ok(board) = board else {
println!("Invalid board string/id");
return;
};
board.pretty_print();
solve_puzzle(board);
} else {
println!("Use --help to see available options");
}
}
@ -100,6 +105,10 @@ struct Args {
print: bool,
#[argh(option, short = 's')]
/// the board to solve
solve: Option<String>,
/// the id of the board to solve
solve: Option<u128>,
#[argh(option)]
/// the board to solve in board representation
solve_board: Option<String>,
}