use super::Algorithm;
use crate::maze::grid::{Grid, cell::Cell};
use crate::utils::types::Coords;
use clap::ValueEnum;
use rand::prelude::*;
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, ValueEnum)]
pub enum Method {
Newest,
Oldest,
Random,
Middle,
Newest50Random50,
Newest75Random25,
Newest25Random75,
}
pub struct GrowingTree {
method: Method,
}
impl GrowingTree {
pub const fn new(method: Method) -> GrowingTree {
GrowingTree { method }
}
fn choose_index<R: Rng>(&self, ceil: usize, rng: &mut R) -> usize {
match self.method {
Method::Oldest => 0,
Method::Newest => ceil - 1,
Method::Middle => ceil / 2,
Method::Random => rng.random_range(0..ceil),
Method::Newest50Random50 => {
let is_newest: bool = rng.random();
if is_newest {
ceil - 1
} else {
rng.random_range(0..ceil)
}
}
Method::Newest75Random25 => {
let prob: f32 = rng.random();
if prob < 0.75 {
ceil - 1
} else {
rng.random_range(0..ceil)
}
}
Method::Newest25Random75 => {
let prob: f32 = rng.random();
if prob < 0.25 {
ceil - 1
} else {
rng.random_range(0..ceil)
}
}
}
}
}
impl Algorithm for GrowingTree {
fn generate(&mut self, grid: &mut Grid, rng: &mut StdRng) {
let mut directions = [Cell::NORTH, Cell::SOUTH, Cell::WEST, Cell::EAST];
let mut cells = vec![];
cells.push(get_rand_coords(grid, rng));
while !cells.is_empty() {
let mut index = Some(self.choose_index(cells.len(), rng));
let coords = cells[index.unwrap_or(0)];
directions.shuffle(rng);
for dir in directions {
let next = match grid.get_next_cell_coords(coords, dir) {
Ok(next) => next,
Err(_) => continue,
};
if grid.is_cell_visited(next) {
continue;
}
if let Ok(next) = grid.carve_passage(coords, dir) {
cells.push(next);
index = None;
break;
}
}
if let Some(index) = index {
cells.remove(index);
}
}
}
}
fn get_rand_coords<R: Rng>(grid: &Grid, rng: &mut R) -> Coords {
let x = rng.random_range(0..grid.width());
let y = rng.random_range(0..grid.height());
(x, y)
}