Add generator

This commit is contained in:
cool-mist
2025-01-04 22:30:46 +05:30
parent d6119de05a
commit 354b59c004
7 changed files with 310 additions and 1 deletions
+12
View File
@@ -88,6 +88,18 @@ impl Board {
}
}
pub(crate) fn empty_squares(&self) -> Vec<Coord> {
let mut empty_squares = Vec::new();
for file in 0..4 {
for rank in 0..4 {
if self.cells[file][rank].is_empty() {
empty_squares.push(Coord::new(file, rank));
}
}
}
empty_squares
}
pub(crate) fn print(&self) -> String {
let mut builder: Vec<char> = Vec::new();
for rank in 0..4 {
+86
View File
@@ -0,0 +1,86 @@
use crate::{
engine::{board::Board, coord::Coord, piece::Piece, square::Square},
solver::{self, solver::Solver},
};
use rand::{seq::*, Rng};
pub(crate) fn generate() -> Option<Board> {
let mut rand = rand::thread_rng();
let candidate_pieces = vec![
Piece::Pawn,
Piece::Pawn,
Piece::Pawn,
Piece::Rook,
Piece::Bishop,
Piece::Knight,
Piece::Knight,
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());
if let Some(board) = board {
return Some(board);
}
}
None
}
fn try_generate(
num_pieces: u32,
mut candidate_pieces: Vec<Piece>,
mut rand: rand::prelude::ThreadRng,
) -> Option<Board> {
let mut board = Board::new();
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;
}
attempts -= 1;
let index = rand.gen_range(0..candidate_pieces.len());
let piece = candidate_pieces[index];
let coord = empty_squares.choose(&mut rand).unwrap().clone();
board.set(Square::Occupied(piece.clone(), coord.clone()));
let solutions = Solver::new(board.clone()).solve();
if solutions.len() > 0 {
placed = true;
candidate_pieces.remove(index);
continue;
}
board.set(Square::Empty(coord));
}
}
let solutions = Solver::new(board.clone()).solve();
if solutions.len() > 1 {
None
} else {
Some(board)
}
}
#[cfg(test)]
mod tests {
use crate::{engine::board::GameState, solver::solver::Solver};
use super::*;
#[test]
fn generator_smoke() {
let board = generate().unwrap();
assert_eq!(board.game_state, GameState::InProgress);
let solutions = Solver::new(board).solve();
assert_ne!(solutions.len(), 0);
}
}
+1
View File
@@ -0,0 +1 @@
pub(crate) mod generator;
+31 -1
View File
@@ -4,4 +4,34 @@ mod engine;
#[allow(unused)]
mod solver;
fn main() {}
#[allow(unused)]
mod generator;
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();
println!("Generated a problem in {} ms", elapsed.as_millis());
let Some(board) = board else {
println!(
"Failed to generate a board after {} ms, Try again",
elapsed.as_millis()
);
return;
};
println!("{}", board.print());
let solutions = Solver::new(board).solve();
println!("Found {} solutions", solutions.len());
let solution = solutions.first().unwrap();
let mut idx = 0;
solution.iter().for_each(|m| {
idx += 1;
println!("{}. {}", idx, m.notation());
});
}