enable tests

This commit is contained in:
cool-mist
2025-05-11 23:10:02 +05:30
parent c1b0ea24a6
commit 654469bb4a
6 changed files with 153 additions and 40 deletions
+10 -2
View File
@@ -1,9 +1,17 @@
use argh::FromArgs;
use sol_chess::board::Board;
use sol_chess::generator;
use sol_chess::generator::{self, RandomRange};
use sol_chess::solver::Solver;
// Learn how to specify a different dependency for this binary
struct MacroquadRngTodo;
impl RandomRange for MacroquadRngTodo {
fn gen_range(&self, min: usize, max: usize) -> usize {
macroquad::rand::gen_range(min, max)
}
}
fn main() {
let args: Args = argh::from_env();
@@ -65,7 +73,7 @@ fn generate_puzzle(num_pieces: Option<u32>, num_solutions: Option<u32>) -> Optio
"Generating a puzzle with {} pieces with a maximum of {} solutions",
num_pieces, num_solutions
);
let gen = generator::generate(num_pieces, num_solutions);
let gen = generator::generate(num_pieces, num_solutions, &MacroquadRngTodo);
gen.print_stats();
let Some(board) = gen.board() else {
+10 -3
View File
@@ -4,16 +4,23 @@ use std::{
};
use button::Button;
use macroquad::{math, prelude::*};
use macroquad::{math, prelude::*, rand};
use sol_chess::{
board::{Board, BoardState},
generator,
generator::{self, RandomRange},
};
use texture::PieceTexture;
pub mod button;
pub mod texture;
pub struct MacroquadRandAdapter;
impl RandomRange for MacroquadRandAdapter {
fn gen_range(&self, min: usize, max: usize) -> usize {
rand::gen_range(min, max)
}
}
pub struct Game {
// The generated puzzle. We keep a copy of this to reset the game.
original_board: Board,
@@ -445,7 +452,7 @@ impl Game {
fn next_puzzle(&mut self) {
self.reset();
let generate = generator::generate(6, 100);
let generate = generator::generate(6, 100, &MacroquadRandAdapter);
let board = generate.board().expect("No puzzle was generated");
self.original_board = board.clone();
self.board = board;
+24 -30
View File
@@ -5,9 +5,11 @@ use crate::{
solver::Solver,
};
use macroquad::{prelude::rand, time};
pub trait RandomRange {
fn gen_range(&self, min: usize, max: usize) -> usize;
}
pub fn generate(num_pieces: u32, num_solutions: u32) -> GenerateStats {
pub fn generate(num_pieces: u32, num_solutions: u32, rand: &impl RandomRange) -> GenerateStats {
let candidate_pieces = vec![
Piece::Pawn,
Piece::Pawn,
@@ -33,18 +35,13 @@ pub fn generate(num_pieces: u32, num_solutions: u32) -> GenerateStats {
}
let attempts: u32 = 1000;
let mut overall_stats = GenerateStats::new(0, 0, 0, 0., None);
let mut overall_stats = GenerateStats::new(0, 0, 0, None);
for _ in 0..attempts {
let stats = try_generate(num_pieces, num_solutions, candidate_pieces.clone());
let stats = try_generate(num_pieces, num_solutions, rand, candidate_pieces.clone());
overall_stats.piece_total += stats.piece_total;
overall_stats.piece_success += stats.piece_success;
overall_stats.total += stats.total;
overall_stats.total_seconds += stats.total_seconds;
overall_stats.board = stats.board;
println!(
"Generating puzzle.. Elapsed: {}s",
overall_stats.total_seconds,
);
if overall_stats.board.is_some() {
return overall_stats;
}
@@ -57,23 +54,15 @@ pub struct GenerateStats {
piece_total: u32,
piece_success: u32,
total: u32,
total_seconds: f64,
board: Option<Board>,
}
impl GenerateStats {
fn new(
piece_total: u32,
piece_success: u32,
total: u32,
total_millis: f64,
board: Option<Board>,
) -> Self {
fn new(piece_total: u32, piece_success: u32, total: u32, board: Option<Board>) -> Self {
Self {
piece_total,
piece_success,
total,
total_seconds: total_millis,
board,
}
}
@@ -83,7 +72,6 @@ impl GenerateStats {
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_seconds);
println!("{}", stats);
}
@@ -103,28 +91,27 @@ where
fn try_generate(
num_pieces: u32,
num_solutions: u32,
rand: &impl RandomRange,
mut candidate_pieces: Vec<Piece>,
) -> GenerateStats {
let mut board = Board::new();
let mut piece_total = 0;
let mut piece_success = 0;
let now = time::get_time();
for _ in 0..num_pieces {
let mut placed = false;
let empty_squares = board.empty_squares();
let mut attempts = 15;
while !placed {
if attempts == 0 {
let elapsed = time::get_time() - now;
return GenerateStats::new(piece_total, piece_success, 1, elapsed, None);
return GenerateStats::new(piece_total, piece_success, 1, None);
}
attempts -= 1;
piece_total += 1;
let index = rand::gen_range(0, candidate_pieces.len());
let index = rand.gen_range(0, candidate_pieces.len());
let piece = candidate_pieces[index];
let square_index = rand::gen_range(0, empty_squares.len());
let square_index = rand.gen_range(0, empty_squares.len());
let mut random_square = empty_squares[square_index].clone();
random_square.piece = Some(piece);
board.set(random_square.clone());
@@ -142,11 +129,10 @@ fn try_generate(
}
let solutions = Solver::new(board.clone()).solve();
let elapsed = time::get_time() - now;
if solutions.len() > num_solutions as usize {
GenerateStats::new(piece_total, piece_success, 1, elapsed, None)
GenerateStats::new(piece_total, piece_success, 1, None)
} else {
GenerateStats::new(piece_total, piece_success, 1, elapsed, Some(board))
GenerateStats::new(piece_total, piece_success, 1, Some(board))
}
}
@@ -156,11 +142,19 @@ mod tests {
use super::*;
// Figure out a way to remove the macroquad dependencies from this package
// #[test]
use rand::Rng;
struct TestRandom;
impl RandomRange for TestRandom {
fn gen_range(&self, min: usize, max: usize) -> usize {
rand::rng().random_range(min..max)
}
}
#[test]
fn generator_smoke() {
for _ in 0..10 {
let gen_stats = generate(5, 5);
let gen_stats = generate(5, 5, &TestRandom);
let board = gen_stats.board.expect("No puzzle was generated");
assert_eq!(board.game_state, BoardState::InProgress);
+2 -2
View File
@@ -1,4 +1,4 @@
use game::Game;
use game::{Game, MacroquadRandAdapter};
use macroquad::prelude::*;
use miniquad::date;
use sol_chess::generator;
@@ -37,7 +37,7 @@ async fn init() -> Game {
let texture_res = Texture2D::from_file_with_format(&texture_bytes[..], None);
texture_res.set_filter(FilterMode::Nearest);
build_textures_atlas();
let generate = generator::generate(6, 100);
let generate = generator::generate(6, 100, &MacroquadRandAdapter);
let board = generate.board().expect("No puzzle was generated");
let game = Game::new(board, texture_res);