diff --git a/src/bin/sol_cli.rs b/src/bin/sol_cli.rs index 45435d9..f85972b 100644 --- a/src/bin/sol_cli.rs +++ b/src/bin/sol_cli.rs @@ -29,7 +29,7 @@ fn main() { 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) + Board::from_id(&board_id) } else { println!("Use --help to see available options"); return; @@ -106,7 +106,7 @@ struct Args { #[argh(option, short = 's')] /// the id of the board to solve - solve: Option, + solve: Option, #[argh(option)] /// the board to solve in board representation diff --git a/src/board.rs b/src/board.rs index d09fa47..6505b22 100644 --- a/src/board.rs +++ b/src/board.rs @@ -17,6 +17,8 @@ use errors::SError; use piece::Piece; use square::{Square, SquarePair}; +use crate::util; + #[derive(Clone)] pub struct Board { pub cells: [[Option; BOARD_SIZE]; BOARD_SIZE], @@ -43,12 +45,20 @@ impl Board { } } - pub fn from_id(board_id: u128) -> Result { + pub fn from_id(board_id: &str) -> Result { + let mut board_id_bytes = [0; 8]; + board_id_bytes.copy_from_slice(board_id.as_bytes()); + let mut working_bytes_slice = [0; 6]; + util::b64_decode_48(&board_id_bytes, &mut working_bytes_slice); + + let mut working_bytes = [0; 8]; + working_bytes[2..].copy_from_slice(&working_bytes_slice); + let mut working = u64::from_be_bytes(working_bytes); + let mut board = Board::new(); - let mut working = board_id; + let mask = 0b111; 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?; @@ -136,21 +146,24 @@ impl Board { pub fn pretty_print(&self) { println!("{}", self.print(true)); + // println!("{:^40}\n", format!("id: {:#018x}", self.id())); println!("{:^40}\n", format!("id: {}", self.id())); } - pub fn id(&self) -> u128 { - let mut res: u128 = 0; + pub fn id(&self) -> String { + let mut res: u64 = 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 = res | byte as u64 } } - res + let mut id_bytes = [0; 6]; + id_bytes.copy_from_slice(&res.to_be_bytes()[2..]); + util::b64_encode_48(&id_bytes) } fn print(&self, pretty: bool) -> String { @@ -585,7 +598,7 @@ mod tests { board.set(sq!("Nc4")); let id = board.id(); - let board2 = Board::from_id(id); + let board2 = Board::from_id(&id); let board2 = board2.unwrap(); validate_board!(board2, "..NB", "....", "RQ.K", "P..."); diff --git a/src/lib.rs b/src/lib.rs index be02fcd..f1f42dd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,3 +1,4 @@ pub mod board; pub mod generator; pub mod solver; +pub mod util; diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..0bf9a0a --- /dev/null +++ b/src/util.rs @@ -0,0 +1,44 @@ +pub(crate) fn b64_encode_48(input: &[u8; 6]) -> String { + let mut output = [0 as char; 8]; + for (byte_chunk, output_slice) in input.chunks_exact(3).zip(output.chunks_exact_mut(4)) { + let byte1 = byte_chunk[0]; + let byte2 = byte_chunk[1]; + let byte3 = byte_chunk[2]; + + output_slice[0] = lookup((byte1 & 0b1111_1100) >> 2); + output_slice[1] = lookup((byte1 & 0b0000_0011) << 4 | (byte2 & 0b1111_0000) >> 4); + output_slice[2] = lookup((byte2 & 0b0000_1111) << 2 | (byte3 & 0b1100_0000) >> 6); + output_slice[3] = lookup(byte3 & 0b0011_1111); + } + + output.iter().collect() +} + +pub(crate) fn b64_decode_48(input: &[u8; 8], output: &mut [u8; 6]) { + for (char_chunk, output_slice) in input.chunks_exact(4).zip(output.chunks_exact_mut(3)) { + let char_1 = reverse_lookup(char_chunk[0] as char); + let char_2 = reverse_lookup(char_chunk[1] as char); + let char_3 = reverse_lookup(char_chunk[2] as char); + let char_4 = reverse_lookup(char_chunk[3] as char); + + output_slice[0] = (char_1 << 2) | (char_2 >> 4); + output_slice[1] = (char_2 << 4) | (char_3 >> 2); + output_slice[2] = (char_3 << 6) | char_4; + } +} + +const ALPHABET: &str = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + +fn lookup(idx: u8) -> char { + ALPHABET + .chars() + .nth(idx as usize) + .unwrap() +} + +fn reverse_lookup(c: char) -> u8 { + ALPHABET + .chars() + .position(|x| x == c) + .unwrap() as u8 +}