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.
|
# It is not intended for manual editing.
|
||||||
version = 3
|
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]]
|
[[package]]
|
||||||
name = "byteorder"
|
name = "byteorder"
|
||||||
version = "1.5.0"
|
version = "1.5.0"
|
||||||
@ -88,10 +120,37 @@ dependencies = [
|
|||||||
"getrandom",
|
"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]]
|
[[package]]
|
||||||
name = "sol_chess"
|
name = "sol_chess"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"argh",
|
||||||
"rand",
|
"rand",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -4,4 +4,5 @@ version = "0.1.0"
|
|||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
argh = "0.1.13"
|
||||||
rand = "0.8.5"
|
rand = "0.8.5"
|
||||||
|
54
README.md
54
README.md
@ -2,6 +2,60 @@
|
|||||||
|
|
||||||
Goal: Generate 'hard' puzzles.
|
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
|
## Heuristics of current algorithm
|
||||||
|
|
||||||
1. About 6-7 pieces on the board.
|
1. About 6-7 pieces on the board.
|
||||||
|
@ -353,6 +353,36 @@ impl Board {
|
|||||||
fn create_move(start: &Square, target: Square) -> Move {
|
fn create_move(start: &Square, target: Square) -> Move {
|
||||||
Move::new(start.clone(), target)
|
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)]
|
#[cfg(test)]
|
||||||
|
@ -12,7 +12,11 @@ impl Move {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn notation(&self) -> String {
|
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};
|
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 mut rand = rand::thread_rng();
|
||||||
let candidate_pieces = vec![
|
let candidate_pieces = vec![
|
||||||
Piece::Pawn,
|
Piece::Pawn,
|
||||||
@ -17,7 +17,6 @@ pub(crate) fn generate() -> Option<Board> {
|
|||||||
Piece::King,
|
Piece::King,
|
||||||
Piece::Queen,
|
Piece::Queen,
|
||||||
];
|
];
|
||||||
let num_pieces = 7;
|
|
||||||
let attempts = 1000;
|
let attempts = 1000;
|
||||||
for i in 0..attempts {
|
for i in 0..attempts {
|
||||||
let board = try_generate(num_pieces, candidate_pieces.clone(), rand.clone());
|
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)]
|
#[allow(unused)]
|
||||||
mod generator;
|
mod generator;
|
||||||
|
|
||||||
|
use argh::FromArgs;
|
||||||
|
use engine::board::Board;
|
||||||
|
|
||||||
use crate::generator::generator::generate;
|
use crate::generator::generator::generate;
|
||||||
use crate::solver::solver::Solver;
|
use crate::solver::solver::Solver;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let start = std::time::Instant::now();
|
let args: Args = argh::from_env();
|
||||||
let board = generate();
|
if args.generate {
|
||||||
let elapsed = start.elapsed();
|
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 {
|
if args.print {
|
||||||
println!(
|
solve_puzzle(board);
|
||||||
"Failed to generate a board after {} ms, Try again",
|
}
|
||||||
elapsed.as_millis()
|
} else if let Some(board_string) = args.solve {
|
||||||
);
|
let board = Board::from_string(board_string);
|
||||||
return;
|
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();
|
let solutions = Solver::new(board).solve();
|
||||||
|
if solutions.len() == 0 {
|
||||||
|
println!("No solutions found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
println!("Found {} solutions", solutions.len());
|
println!("Found {} solutions", solutions.len());
|
||||||
let solution = solutions.first().unwrap();
|
let solution = solutions.first().unwrap();
|
||||||
let mut idx = 0;
|
let mut idx = 0;
|
||||||
@ -35,3 +53,47 @@ fn main() {
|
|||||||
println!("{}. {}", idx, m.notation());
|
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