Add ID for a board
This commit is contained in:
parent
32ec8107ab
commit
61b71eb8f0
@ -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
4
src/engine/errors.rs
Normal file
@ -0,0 +1,4 @@
|
||||
#[derive(Debug)]
|
||||
pub(crate) enum SError {
|
||||
InvalidBoard,
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
pub(crate) mod constants;
|
||||
pub(crate) mod errors;
|
||||
pub(crate) mod board;
|
||||
pub(crate) mod square;
|
||||
pub(crate) mod cmove;
|
||||
|
@ -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() {
|
||||
|
25
src/main.rs
25
src/main.rs
@ -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>,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user