use std::fmt::Debug;
use rand::{seq::SliceRandom, Rng};
use crate::Grid;
#[derive(Clone, PartialEq, Debug)]
pub(crate) enum PixelChangeResult {
Unchanged,
Updated,
Invalid,
}
pub trait PossibleValues: Sized + Clone + Eq {
fn get_possible_values() -> Vec<(Self, f32)>;
}
#[derive(Clone)]
pub struct Pixel<T: Clone> {
pub(crate) possible_values: Vec<(T, f32)>,
pub determined_value: Option<T>,
}
impl<T: PossibleValues> Default for Pixel<T> {
fn default() -> Self {
Self {
possible_values: T::get_possible_values(),
determined_value: None,
}
}
}
impl<T: PossibleValues> Pixel<T> {
pub fn new(item: T) -> Pixel<T> {
Pixel {
possible_values: vec![(item.clone(), 1f32)],
determined_value: Some(item),
}
}
pub(crate) fn recalc<const D: usize, F>(
&mut self,
grid: &Grid<T, D>,
location: [usize; D],
test: F,
randomize: Option<&mut impl Rng>,
) -> PixelChangeResult
where
F: Fn(&Grid<T, D>, [usize; D], &T, f32) -> (bool, f32),
{
let mut r = PixelChangeResult::Unchanged;
let len = self.possible_values.len();
for (i, val) in self.possible_values.clone().iter().rev().enumerate() {
let (ok, probability) = test(grid, location, &val.0, val.1);
if !ok {
self.possible_values.remove(len - i - 1);
r = PixelChangeResult::Updated;
} else {
self.possible_values[len - i - 1].1 = probability;
}
}
if self.possible_values.is_empty() {
return PixelChangeResult::Invalid; }
if self.determined_value.is_some() {
return PixelChangeResult::Unchanged;
}
if self.possible_values.len() == 1 {
self.determined_value = Some(self.possible_values[0].0.clone());
return PixelChangeResult::Updated;
}
if let Some(rng) = randomize {
self.determined_value = Some(
self.possible_values
.choose_weighted(rng, |(_, x)| *x)
.unwrap()
.0
.clone(),
);
self.possible_values = vec![(self.determined_value.as_ref().unwrap().clone(), 1f32)];
r = PixelChangeResult::Updated;
}
r
}
}