Add as command line tool
This commit is contained in:
parent
354b59c004
commit
be9585d5c2
59
Cargo.lock
generated
59
Cargo.lock
generated
@ -2,6 +2,38 @@
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "argh"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34ff18325c8a36b82f992e533ece1ec9f9a9db446bd1c14d4f936bac88fcd240"
|
||||
dependencies = [
|
||||
"argh_derive",
|
||||
"argh_shared",
|
||||
"rust-fuzzy-search",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argh_derive"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb7b2b83a50d329d5d8ccc620f5c7064028828538bdf5646acd60dc1f767803"
|
||||
dependencies = [
|
||||
"argh_shared",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "argh_shared"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a464143cc82dedcdc3928737445362466b7674b5db4e2eb8e869846d6d84f4f6"
|
||||
dependencies = [
|
||||
"serde",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "byteorder"
|
||||
version = "1.5.0"
|
||||
@ -88,10 +120,37 @@ dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-fuzzy-search"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a157657054ffe556d8858504af8a672a054a6e0bd9e8ee531059100c0fa11bb2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "02fc4265df13d6fa1d00ecff087228cc0a2b5f3c0e87e258d8b94a156e984c70"
|
||||
dependencies = [
|
||||
"serde_derive",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "serde_derive"
|
||||
version = "1.0.217"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5a9bf7cf98d04a2b28aead066b7496853d4779c9cc183c440dbac457641e19a0"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sol_chess"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"argh",
|
||||
"rand",
|
||||
]
|
||||
|
||||
|
@ -4,4 +4,5 @@ version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
argh = "0.1.13"
|
||||
rand = "0.8.5"
|
||||
|
54
README.md
54
README.md
@ -2,6 +2,60 @@
|
||||
|
||||
Goal: Generate 'hard' puzzles.
|
||||
|
||||
## Install
|
||||
|
||||
- Install Rust from [here](https://www.rust-lang.org/tools/install).
|
||||
- Run `cargo install --git https://github.com/cool-mist/sol_chess` to install the tool.
|
||||
- Run `sol_chess --help` to see the options.
|
||||
|
||||
## Usage
|
||||
|
||||
- Generate a puzzle
|
||||
|
||||
```bash
|
||||
$ sol_chess -g -n 6
|
||||
Generated a puzzle with 6 pieces after 330 ms
|
||||
PP..
|
||||
..PB
|
||||
.K..
|
||||
.N..
|
||||
```
|
||||
|
||||
- Solve a puzzle
|
||||
|
||||
```bash
|
||||
$ sol_chess -- --solve PP....PB.K...N..
|
||||
PP..
|
||||
..PB
|
||||
.K..
|
||||
.N..
|
||||
|
||||
Found 1 solutions
|
||||
1. Nb1 -> c3
|
||||
2. Nc3 -> a4
|
||||
3. Na4 -> b2
|
||||
4. Nb2 -> d3
|
||||
5. Nd3 -> b4
|
||||
```
|
||||
|
||||
- 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.
|
||||
|
||||
Found 1 solutions
|
||||
1. Ba3 -> b4
|
||||
2. Bb4 -> c3
|
||||
3. Bc3 -> d4
|
||||
4. Bd4 -> b2
|
||||
5. Bb2 -> c1
|
||||
```
|
||||
|
||||
## Heuristics of current algorithm
|
||||
|
||||
1. About 6-7 pieces on the board.
|
||||
|
@ -353,6 +353,36 @@ impl Board {
|
||||
fn create_move(start: &Square, target: Square) -> Move {
|
||||
Move::new(start.clone(), target)
|
||||
}
|
||||
|
||||
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..4 {
|
||||
for f in 0..4 {
|
||||
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::Occupied(piece, Coord::new(f, r));
|
||||
board.set(square);
|
||||
}
|
||||
}
|
||||
Some(board)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -12,7 +12,11 @@ impl Move {
|
||||
}
|
||||
|
||||
pub(crate) fn notation(&self) -> String {
|
||||
format!("{} -> {}", self.from.notation(), self.to.notation())
|
||||
format!(
|
||||
"{} -> {}",
|
||||
self.from.notation(),
|
||||
self.to.coord_ref().notation
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ use crate::{
|
||||
};
|
||||
use rand::{seq::*, Rng};
|
||||
|
||||
pub(crate) fn generate() -> Option<Board> {
|
||||
pub(crate) fn generate(num_pieces: u32) -> Option<Board> {
|
||||
let mut rand = rand::thread_rng();
|
||||
let candidate_pieces = vec![
|
||||
Piece::Pawn,
|
||||
@ -17,7 +17,6 @@ pub(crate) fn generate() -> Option<Board> {
|
||||
Piece::King,
|
||||
Piece::Queen,
|
||||
];
|
||||
let num_pieces = 7;
|
||||
let attempts = 1000;
|
||||
for i in 0..attempts {
|
||||
let board = try_generate(num_pieces, candidate_pieces.clone(), rand.clone());
|
||||
|
86
src/main.rs
86
src/main.rs
@ -7,26 +7,44 @@ mod solver;
|
||||
#[allow(unused)]
|
||||
mod generator;
|
||||
|
||||
use argh::FromArgs;
|
||||
use engine::board::Board;
|
||||
|
||||
use crate::generator::generator::generate;
|
||||
use crate::solver::solver::Solver;
|
||||
|
||||
fn main() {
|
||||
let start = std::time::Instant::now();
|
||||
let board = generate();
|
||||
let elapsed = start.elapsed();
|
||||
let args: Args = argh::from_env();
|
||||
if args.generate {
|
||||
let puzzle = generate_puzzle(args.num_pieces);
|
||||
let Some(board) = puzzle else {
|
||||
return;
|
||||
};
|
||||
|
||||
println!("Generated a problem in {} ms", elapsed.as_millis());
|
||||
println!("{}", board.print());
|
||||
|
||||
let Some(board) = board else {
|
||||
println!(
|
||||
"Failed to generate a board after {} ms, Try again",
|
||||
elapsed.as_millis()
|
||||
);
|
||||
return;
|
||||
};
|
||||
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");
|
||||
return;
|
||||
};
|
||||
println!("{}", board.print());
|
||||
solve_puzzle(board);
|
||||
} else {
|
||||
println!("Use --help to see available options");
|
||||
}
|
||||
}
|
||||
|
||||
println!("{}", board.print());
|
||||
fn solve_puzzle(board: Board) {
|
||||
let solutions = Solver::new(board).solve();
|
||||
if solutions.len() == 0 {
|
||||
println!("No solutions found");
|
||||
return;
|
||||
}
|
||||
println!("Found {} solutions", solutions.len());
|
||||
let solution = solutions.first().unwrap();
|
||||
let mut idx = 0;
|
||||
@ -35,3 +53,47 @@ fn main() {
|
||||
println!("{}. {}", idx, m.notation());
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
let Some(board) = board else {
|
||||
println!(
|
||||
"Failed to generate a puzzle with {} pieces after {} ms, Try again",
|
||||
num_pieces,
|
||||
elapsed.as_millis()
|
||||
);
|
||||
return None;
|
||||
};
|
||||
|
||||
println!(
|
||||
"Generated a puzzle with {} pieces after {} ms",
|
||||
num_pieces,
|
||||
elapsed.as_millis()
|
||||
);
|
||||
Some(board)
|
||||
}
|
||||
|
||||
/// Solitaire Chess puzzle generator and solver
|
||||
/// - v0.0.1 cool-mist
|
||||
#[derive(FromArgs)]
|
||||
struct Args {
|
||||
#[argh(switch, short = 'g')]
|
||||
/// generate a puzzle
|
||||
generate: bool,
|
||||
|
||||
#[argh(option, short = 'n')]
|
||||
/// number of pieces to place on the board while generating a puzzle
|
||||
num_pieces: Option<u32>,
|
||||
|
||||
#[argh(switch)]
|
||||
/// print the solution. When solving a puzzle, this is always set to true
|
||||
print: bool,
|
||||
|
||||
#[argh(option, short = 's')]
|
||||
/// the board to solve
|
||||
solve: Option<String>,
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user