use rand::prelude::*;
use std::collections::HashMap;
use super::row::*;
use super::skill::*;
use super::slab_def::*;
#[derive(PartialEq, PartialOrd)]
struct DefDensity {
def: SlabDef,
density: f64,
}
impl std::cmp::Eq for DefDensity {}
impl std::cmp::Ord for DefDensity {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.def.cmp(&other.def)
}
}
fn build_rng_seed(seed: u64, row_index: usize) -> [u8; 32] {
let mut buf: [u8; 32] = [0; 32];
let buf1 = bincode::serialize(&seed).unwrap();
let mut i: usize = 0;
for v in buf1.into_iter() {
buf[i] = v;
i += 1;
}
let buf2 = bincode::serialize(&row_index).unwrap();
for v in buf2.into_iter() {
buf[i] = v;
i += 1;
}
buf
}
pub fn generate_first_row(seed: u64, width: usize, skill: Skill) -> Row {
let rng_seed = build_rng_seed(seed, 0);
let rng: StdRng = SeedableRng::from_seed(rng_seed);
let def_density = skill.def_density0();
row_from_def_density(rng, width, &def_density)
}
pub fn generate_next_row(seed: u64, j: usize, previous_row: &Row, skill: Skill) -> Row {
let rng_seed = build_rng_seed(seed, j);
let rng: StdRng = SeedableRng::from_seed(rng_seed);
let def_density = skill.def_density();
row_from_previous(rng, previous_row, &def_density, skill.mutability())
}
fn row_from_def_density(
mut rng: impl Rng,
width: usize,
def_density: &HashMap<SlabDef, f64>,
) -> Row {
let mut row = Row::default();
let mut v: Vec<DefDensity> = Vec::new();
for (def, density) in def_density {
v.push(DefDensity {
def: *def,
density: *density,
});
}
v.sort();
for i in 0..width {
let f: f64 = rng.gen();
let mut limit: f64 = 0.0;
for dd in &v {
if f >= limit && f < limit + dd.density {
row.set(i as isize, dd.def);
break;
}
limit += dd.density;
}
}
row
}
fn row_from_previous(
mut rng: impl Rng,
previous_row: &Row,
def_density: &HashMap<SlabDef, f64>,
mutability: f64,
) -> Row {
let mut row = Row::default();
let mut v: Vec<DefDensity> = Vec::new();
for (def, density) in def_density {
v.push(DefDensity {
def: *def,
density: *density,
});
}
v.sort();
for i in 0..(previous_row.slabs.len() as isize) {
let f: f64 = rng.gen();
let mut limit: f64 = 0.0;
for dd in &v {
if f >= limit && f < limit + dd.density {
row.set(i, dd.def);
break;
}
limit += dd.density;
}
let change: f64 = rng.gen();
let previous_def = previous_row.get(i);
if change >= mutability && !previous_def.is_special() && !row.get(i).is_special() {
row.set(i as isize, previous_def);
}
}
row
}