Add progress bar, Add stats, pretty print
This commit is contained in:
parent
69420922bd
commit
b6a6d570e1
218
Cargo.lock
generated
218
Cargo.lock
generated
@ -34,6 +34,12 @@ dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bumpalo"
|
||||
version = "3.16.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
@ -46,6 +52,25 @@ version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "console"
|
||||
version = "0.15.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea3c6ecd8059b57859df5c69830340ed3c41d30e3da0c1cbed90a96ac853041b"
|
||||
dependencies = [
|
||||
"encode_unicode",
|
||||
"libc",
|
||||
"once_cell",
|
||||
"unicode-width",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "encode_unicode"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.15"
|
||||
@ -57,12 +82,59 @@ dependencies = [
|
||||
"wasi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "indicatif"
|
||||
version = "0.17.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cbf675b85ed934d3c67b5c5469701eec7db22689d0a2139d856e0925fa28b281"
|
||||
dependencies = [
|
||||
"console",
|
||||
"number_prefix",
|
||||
"portable-atomic",
|
||||
"unicode-width",
|
||||
"web-time",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "js-sys"
|
||||
version = "0.3.76"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6717b6b5b077764fb5966237269cb3c64edddde4b14ce42647430a78ced9e7b7"
|
||||
dependencies = [
|
||||
"once_cell",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.169"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b5aba8db14291edd000dfcc4d620c7ebfb122c613afb886ca8803fa4e128a20a"
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3d6ea2a48c204030ee31a7d7fc72c93294c92fe87ecb1789881c9543516e1a0d"
|
||||
|
||||
[[package]]
|
||||
name = "number_prefix"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
|
||||
|
||||
[[package]]
|
||||
name = "once_cell"
|
||||
version = "1.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
|
||||
|
||||
[[package]]
|
||||
name = "portable-atomic"
|
||||
version = "1.10.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "280dc24453071f1b63954171985a0b0d30058d287960968b9b2aca264c8d4ee6"
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.20"
|
||||
@ -148,9 +220,10 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "sol_chess"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
dependencies = [
|
||||
"argh",
|
||||
"indicatif",
|
||||
"rand",
|
||||
]
|
||||
|
||||
@ -171,12 +244,155 @@ version = "1.0.14"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1fc81956842c57dac11422a97c3b8195a1ff727f06e85c84ed2e8aa277c9a0fd"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a474f6281d1d70c17ae7aa6a613c87fce69a127e2624002df63dcb39d6cf6396"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"once_cell",
|
||||
"wasm-bindgen-macro",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-backend"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5f89bb38646b4f81674e8f5c3fb81b562be1fd936d84320f3264486418519c79"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"log",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cc6181fd9a7492eef6fef1f33961e3695e4579b9872a6f7c83aee556666d4fe"
|
||||
dependencies = [
|
||||
"quote",
|
||||
"wasm-bindgen-macro-support",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-macro-support"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "30d7a95b763d3c45903ed6c81f156801839e5ee968bb07e534c44df0fcd330c2"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
"wasm-bindgen-backend",
|
||||
"wasm-bindgen-shared",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen-shared"
|
||||
version = "0.2.99"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "943aab3fdaaa029a6e0271b35ea10b72b943135afe9bffca82384098ad0e06a6"
|
||||
|
||||
[[package]]
|
||||
name = "web-time"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb"
|
||||
dependencies = [
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b"
|
||||
dependencies = [
|
||||
"windows-targets",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-targets"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973"
|
||||
dependencies = [
|
||||
"windows_aarch64_gnullvm",
|
||||
"windows_aarch64_msvc",
|
||||
"windows_i686_gnu",
|
||||
"windows_i686_gnullvm",
|
||||
"windows_i686_msvc",
|
||||
"windows_x86_64_gnu",
|
||||
"windows_x86_64_gnullvm",
|
||||
"windows_x86_64_msvc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3"
|
||||
|
||||
[[package]]
|
||||
name = "windows_aarch64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_i686_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnu"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_gnullvm"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d"
|
||||
|
||||
[[package]]
|
||||
name = "windows_x86_64_msvc"
|
||||
version = "0.52.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec"
|
||||
|
||||
[[package]]
|
||||
name = "zerocopy"
|
||||
version = "0.7.35"
|
||||
|
@ -1,10 +1,11 @@
|
||||
[package]
|
||||
name = "sol_chess"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
argh = "0.1.13"
|
||||
indicatif = "0.17.9"
|
||||
rand = "0.8.5"
|
||||
|
||||
[profile.release]
|
||||
|
111
README.md
111
README.md
@ -14,46 +14,67 @@ Goal: Generate 'hard' puzzles.
|
||||
|
||||
```bash
|
||||
$ sol_chess -g -n 6
|
||||
Generated a puzzle with 6 pieces after 330 ms
|
||||
PP..
|
||||
..PB
|
||||
.K..
|
||||
.N..
|
||||
Generating a puzzle with 6 pieces with a maximum of 5 solutions
|
||||
Total attempts: 7
|
||||
Total pieces placed: 71
|
||||
Success pieces placed: 42
|
||||
Total time (ms): 69
|
||||
|
||||
♘ . . .
|
||||
|
||||
♙ . ♖ .
|
||||
|
||||
♔ . ♘ ♙
|
||||
|
||||
. . . .
|
||||
```
|
||||
|
||||
- Solve a puzzle
|
||||
|
||||
```bash
|
||||
$ sol_chess -- --solve PP....PB.K...N..
|
||||
PP..
|
||||
..PB
|
||||
.K..
|
||||
.N..
|
||||
$ sol_chess -- --solve N...P.R.K.NP....
|
||||
♘ . . .
|
||||
|
||||
Found 1 solutions
|
||||
1. Nb1 -> c3
|
||||
2. Nc3 -> a4
|
||||
3. Na4 -> b2
|
||||
4. Nb2 -> d3
|
||||
5. Nd3 -> b4
|
||||
♙ . ♖ .
|
||||
|
||||
♔ . ♘ ♙
|
||||
|
||||
. . . .
|
||||
|
||||
|
||||
Found 3 solutions
|
||||
1. Rc3 -> a3
|
||||
2. Ra3 -> a4
|
||||
3. Ra4 -> a2
|
||||
4. Ra2 -> c2
|
||||
5. Rc2 -> d2
|
||||
```
|
||||
|
||||
- Generate and solve a puzzle
|
||||
|
||||
```bash
|
||||
$ sol_chess -g -n 6 --print
|
||||
Generated a puzzle with 6 pieces after 933 ms
|
||||
.P.N
|
||||
B.R.
|
||||
.K..
|
||||
..N.
|
||||
Generating a puzzle with 6 pieces with a maximum of 5 solutions
|
||||
Total attempts: 4
|
||||
Total pieces placed: 34
|
||||
Success pieces placed: 24
|
||||
Total time (ms): 38
|
||||
|
||||
Found 1 solutions
|
||||
1. Ba3 -> b4
|
||||
2. Bb4 -> c3
|
||||
3. Bc3 -> d4
|
||||
4. Bd4 -> b2
|
||||
5. Bb2 -> c1
|
||||
. . ♙ .
|
||||
|
||||
♕ . . ♘
|
||||
|
||||
. . . .
|
||||
|
||||
♗ ♖ . ♘
|
||||
|
||||
|
||||
Found 5 solutions
|
||||
1. Rb1 -> a1
|
||||
2. Ra1 -> d1
|
||||
3. Rd1 -> d3
|
||||
4. Qa3 -> d3
|
||||
5. Qd3 -> c4
|
||||
```
|
||||
|
||||
## Heuristics of current algorithm
|
||||
@ -62,40 +83,4 @@ Found 1 solutions
|
||||
2. Select pieces to place based on its weight.
|
||||
3. Eg: Queen is too powerful, so it has lower weightage.
|
||||
4. Eg: Knights are confusing. More knights.
|
||||
3. Discard puzzles with more than one solution.
|
||||
|
||||
## Example puzzles generated
|
||||
|
||||
1.
|
||||
|
||||
```
|
||||
N...
|
||||
P.B.
|
||||
.R..
|
||||
..KP
|
||||
```
|
||||
|
||||
2.
|
||||
|
||||
```
|
||||
R...
|
||||
..P.
|
||||
..B.
|
||||
.KNN
|
||||
```
|
||||
3.
|
||||
|
||||
```
|
||||
.PN.
|
||||
P...
|
||||
K..P
|
||||
.R..
|
||||
```
|
||||
|
||||
4.
|
||||
|
||||
```
|
||||
..PK
|
||||
...R
|
||||
P..P
|
||||
B..N
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::collections::HashSet;
|
||||
use std::{collections::HashSet, fmt::Display};
|
||||
|
||||
use super::{
|
||||
coord::{at, Coord},
|
||||
@ -100,24 +100,26 @@ impl Board {
|
||||
empty_squares
|
||||
}
|
||||
|
||||
pub(crate) fn print(&self) -> String {
|
||||
let mut builder: Vec<char> = Vec::new();
|
||||
pub(crate) fn pretty_print(&self) {
|
||||
println!("{}", self.print(true));
|
||||
}
|
||||
|
||||
fn print(&self, pretty: bool) -> String {
|
||||
let mut board_string = String::new();
|
||||
for rank in 0..4 {
|
||||
let mut row = String::new();
|
||||
for file in 0..4 {
|
||||
match self.cells[file][rank] {
|
||||
Square::Empty(_) => builder.push('.'),
|
||||
Square::Occupied(Piece::King, _) => builder.push('K'),
|
||||
Square::Occupied(Piece::Queen, _) => builder.push('Q'),
|
||||
Square::Occupied(Piece::Bishop, _) => builder.push('B'),
|
||||
Square::Occupied(Piece::Knight, _) => builder.push('N'),
|
||||
Square::Occupied(Piece::Rook, _) => builder.push('R'),
|
||||
Square::Occupied(Piece::Pawn, _) => builder.push('P'),
|
||||
}
|
||||
print_square(&mut row, &self.cells[file][rank], pretty);
|
||||
}
|
||||
builder.push('\n');
|
||||
if pretty {
|
||||
board_string.push_str(&format!("{:^40}\n", row));
|
||||
} else {
|
||||
board_string.push_str(&row);
|
||||
}
|
||||
board_string.push('\n');
|
||||
}
|
||||
|
||||
builder.iter().collect::<String>()
|
||||
board_string
|
||||
}
|
||||
|
||||
fn calc_legal_moves(&mut self) {
|
||||
@ -385,6 +387,24 @@ impl Board {
|
||||
}
|
||||
}
|
||||
|
||||
fn print_square(row: &mut String, square: &Square, pretty: bool) {
|
||||
let contents = if let Square::Occupied(piece, _) = square {
|
||||
if pretty {
|
||||
piece.pretty()
|
||||
} else {
|
||||
piece.notation()
|
||||
}
|
||||
} else {
|
||||
"."
|
||||
};
|
||||
|
||||
if pretty {
|
||||
row.push_str(&format!(" {} ", contents));
|
||||
} else {
|
||||
row.push_str(contents);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::engine::piece::p;
|
||||
@ -395,7 +415,7 @@ mod tests {
|
||||
|
||||
macro_rules! validate_board {
|
||||
($board:expr, $row1:literal, $row2:literal, $row3:literal, $row4:literal) => {
|
||||
let printed = $board.print();
|
||||
let printed = $board.print(false);
|
||||
assert_eq!(
|
||||
printed,
|
||||
format!("{}\n{}\n{}\n{}\n", $row1, $row2, $row3, $row4)
|
||||
|
@ -31,6 +31,17 @@ impl Piece {
|
||||
Piece::Pawn => "P",
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn pretty(&self) -> &str {
|
||||
match self {
|
||||
Piece::King => "♔",
|
||||
Piece::Queen => "♕",
|
||||
Piece::Bishop => "♗",
|
||||
Piece::Knight => "♘",
|
||||
Piece::Rook => "♖",
|
||||
Piece::Pawn => "♙",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! p {
|
||||
|
@ -1,10 +1,13 @@
|
||||
use std::{fmt::Display, thread::Builder, time::Duration};
|
||||
|
||||
use crate::{
|
||||
engine::{board::Board, coord::Coord, piece::Piece, square::Square},
|
||||
solver::{self, solver::Solver},
|
||||
};
|
||||
use indicatif::ProgressBar;
|
||||
use rand::{seq::*, Rng};
|
||||
|
||||
pub(crate) fn generate(num_pieces: u32) -> Option<Board> {
|
||||
pub(crate) fn generate(num_pieces: u32, num_solutions: u32) -> GenerateStats {
|
||||
let mut rand = rand::thread_rng();
|
||||
let candidate_pieces = vec![
|
||||
Piece::Pawn,
|
||||
@ -17,33 +20,104 @@ pub(crate) fn generate(num_pieces: u32) -> Option<Board> {
|
||||
Piece::King,
|
||||
Piece::Queen,
|
||||
];
|
||||
let attempts = 1000;
|
||||
let attempts: u32 = 1000;
|
||||
let bar = ProgressBar::new_spinner();
|
||||
bar.enable_steady_tick(Duration::from_millis(100));
|
||||
let mut overall_stats = GenerateStats::new(0, 0, 0, 0, None);
|
||||
for i in 0..attempts {
|
||||
let board = try_generate(num_pieces, candidate_pieces.clone(), rand.clone());
|
||||
if let Some(board) = board {
|
||||
return Some(board);
|
||||
let stats = try_generate(
|
||||
num_pieces,
|
||||
num_solutions,
|
||||
candidate_pieces.clone(),
|
||||
rand.clone(),
|
||||
);
|
||||
overall_stats.piece_total += stats.piece_total;
|
||||
overall_stats.piece_success += stats.piece_success;
|
||||
overall_stats.total += stats.total;
|
||||
overall_stats.total_millis += stats.total_millis;
|
||||
overall_stats.board = stats.board;
|
||||
bar.set_message(format!(
|
||||
"Generating puzzle.. Elapsed: {}s",
|
||||
overall_stats.total_millis / 1000
|
||||
));
|
||||
if overall_stats.board.is_some() {
|
||||
return overall_stats;
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
bar.finish_and_clear();
|
||||
overall_stats
|
||||
}
|
||||
|
||||
pub(crate) struct GenerateStats {
|
||||
piece_total: u32,
|
||||
piece_success: u32,
|
||||
total: u32,
|
||||
total_millis: u128,
|
||||
board: Option<Board>,
|
||||
}
|
||||
|
||||
impl GenerateStats {
|
||||
fn new(
|
||||
piece_total: u32,
|
||||
piece_success: u32,
|
||||
total: u32,
|
||||
total_millis: u128,
|
||||
board: Option<Board>,
|
||||
) -> Self {
|
||||
Self {
|
||||
piece_total,
|
||||
piece_success,
|
||||
total,
|
||||
total_millis,
|
||||
board,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn print_stats(&self) {
|
||||
let mut stats = String::new();
|
||||
add_stat(&mut stats, "Total attempts", self.total);
|
||||
add_stat(&mut stats, "Total pieces placed", self.piece_total);
|
||||
add_stat(&mut stats, "Success pieces placed", self.piece_success);
|
||||
add_stat(&mut stats, "Total time (ms)", self.total_millis);
|
||||
|
||||
println!("{}", stats);
|
||||
}
|
||||
|
||||
pub(crate) fn board(mut self) -> Option<Board> {
|
||||
self.board
|
||||
}
|
||||
}
|
||||
|
||||
fn add_stat<T>(stats: &mut String, name: &str, val: T)
|
||||
where
|
||||
T: Display,
|
||||
{
|
||||
stats.push_str(&format!("{:>30}:{:>6}\n", name, val));
|
||||
}
|
||||
|
||||
fn try_generate(
|
||||
num_pieces: u32,
|
||||
num_solutions: u32,
|
||||
mut candidate_pieces: Vec<Piece>,
|
||||
mut rand: rand::prelude::ThreadRng,
|
||||
) -> Option<Board> {
|
||||
) -> GenerateStats {
|
||||
let mut board = Board::new();
|
||||
let mut piece_total = 0;
|
||||
let mut piece_success = 0;
|
||||
let mut now = std::time::Instant::now();
|
||||
for _ in 0..num_pieces {
|
||||
let mut placed = false;
|
||||
let empty_squares = board.empty_squares();
|
||||
let mut attempts = 15;
|
||||
while !placed {
|
||||
if attempts == 0 {
|
||||
return None;
|
||||
let elapsed = now.elapsed().as_millis();
|
||||
return GenerateStats::new(piece_total, piece_success, 1, elapsed, None);
|
||||
}
|
||||
|
||||
attempts -= 1;
|
||||
piece_total += 1;
|
||||
|
||||
let index = rand.gen_range(0..candidate_pieces.len());
|
||||
let piece = candidate_pieces[index];
|
||||
@ -53,6 +127,7 @@ fn try_generate(
|
||||
let solutions = Solver::new(board.clone()).solve();
|
||||
if solutions.len() > 0 {
|
||||
placed = true;
|
||||
piece_success += 1;
|
||||
candidate_pieces.remove(index);
|
||||
continue;
|
||||
}
|
||||
@ -61,10 +136,11 @@ fn try_generate(
|
||||
}
|
||||
|
||||
let solutions = Solver::new(board.clone()).solve();
|
||||
if solutions.len() > 1 {
|
||||
None
|
||||
let elapsed = now.elapsed().as_millis();
|
||||
if solutions.len() > num_solutions as usize {
|
||||
GenerateStats::new(piece_total, piece_success, 1, elapsed, None)
|
||||
} else {
|
||||
Some(board)
|
||||
GenerateStats::new(piece_total, piece_success, 1, elapsed, Some(board))
|
||||
}
|
||||
}
|
||||
|
||||
@ -77,11 +153,13 @@ mod tests {
|
||||
#[test]
|
||||
fn generator_smoke() {
|
||||
for _ in 0..10 {
|
||||
let board = generate(5).unwrap();
|
||||
let gen_stats = generate(5, 5);
|
||||
let board = gen_stats.board.unwrap();
|
||||
assert_eq!(board.game_state, GameState::InProgress);
|
||||
|
||||
let solutions = Solver::new(board).solve();
|
||||
assert_eq!(solutions.len(), 1);
|
||||
assert!(solutions.len() <= 5);
|
||||
assert!(solutions.len() >= 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
46
src/main.rs
46
src/main.rs
@ -16,13 +16,12 @@ use crate::solver::solver::Solver;
|
||||
fn main() {
|
||||
let args: Args = argh::from_env();
|
||||
if args.generate {
|
||||
let puzzle = generate_puzzle(args.num_pieces);
|
||||
let puzzle = generate_puzzle(args.num_pieces, args.solutions);
|
||||
let Some(board) = puzzle else {
|
||||
return;
|
||||
};
|
||||
|
||||
println!("{}", board.print());
|
||||
|
||||
board.pretty_print();
|
||||
if args.print {
|
||||
solve_puzzle(board);
|
||||
}
|
||||
@ -32,7 +31,7 @@ fn main() {
|
||||
println!("Invalid board string");
|
||||
return;
|
||||
};
|
||||
println!("{}", board.print());
|
||||
board.pretty_print();
|
||||
solve_puzzle(board);
|
||||
} else {
|
||||
println!("Use --help to see available options");
|
||||
@ -54,26 +53,29 @@ fn solve_puzzle(board: Board) {
|
||||
});
|
||||
}
|
||||
|
||||
fn generate_puzzle(num_pieces: Option<u32>) -> Option<Board> {
|
||||
let start = std::time::Instant::now();
|
||||
let num_pieces = num_pieces.unwrap_or(5);
|
||||
let board = generate(num_pieces);
|
||||
let elapsed = start.elapsed();
|
||||
fn generate_puzzle(num_pieces: Option<u32>, num_solutions: Option<u32>) -> Option<Board> {
|
||||
let mut num_pieces = num_pieces.unwrap_or(5);
|
||||
if num_pieces < 2 {
|
||||
num_pieces = 2;
|
||||
}
|
||||
|
||||
let Some(board) = board else {
|
||||
println!(
|
||||
"Failed to generate a puzzle with {} pieces after {} ms, Try again",
|
||||
num_pieces,
|
||||
elapsed.as_millis()
|
||||
);
|
||||
let mut num_solutions = num_solutions.unwrap_or(5);
|
||||
if num_solutions < 1 {
|
||||
num_solutions = 5;
|
||||
}
|
||||
|
||||
println!(
|
||||
"Generating a puzzle with {} pieces with a maximum of {} solutions",
|
||||
num_pieces, num_solutions
|
||||
);
|
||||
let gen = generate(num_pieces, num_solutions);
|
||||
gen.print_stats();
|
||||
|
||||
let Some(board) = gen.board() else {
|
||||
println!("Failed to generate a puzzle, try again");
|
||||
return None;
|
||||
};
|
||||
|
||||
println!(
|
||||
"Generated a puzzle with {} pieces after {} ms",
|
||||
num_pieces,
|
||||
elapsed.as_millis()
|
||||
);
|
||||
Some(board)
|
||||
}
|
||||
|
||||
@ -89,6 +91,10 @@ struct Args {
|
||||
/// number of pieces to place on the board while generating a puzzle
|
||||
num_pieces: Option<u32>,
|
||||
|
||||
#[argh(option)]
|
||||
/// maximum number of solutions allowed for the generated puzzle. atleast 1. defaults to 5
|
||||
solutions: Option<u32>,
|
||||
|
||||
#[argh(switch)]
|
||||
/// print the solution. When solving a puzzle, this is always set to true
|
||||
print: bool,
|
||||
|
Loading…
x
Reference in New Issue
Block a user