102 lines
2.8 KiB
Rust
102 lines
2.8 KiB
Rust
use rand::Rng;
|
|
use servicepoint2::{ByteGrid, PixelGrid, TILE_HEIGHT, TILE_WIDTH};
|
|
|
|
pub(crate) struct Game {
|
|
pub field: PixelGrid,
|
|
pub luma: ByteGrid,
|
|
}
|
|
|
|
impl Game {
|
|
pub fn step(&mut self) {
|
|
let mut rng = rand::thread_rng();
|
|
|
|
self.field = self.field_iteration();
|
|
|
|
if rng.gen_ratio(1, 10) {
|
|
self.luma = self.luma_iteration();
|
|
}
|
|
}
|
|
|
|
fn field_iteration(&self) -> PixelGrid {
|
|
let mut next = self.field.clone();
|
|
for x in 0..self.field.width() {
|
|
for y in 0..self.field.height() {
|
|
let old_state = self.field.get(x, y);
|
|
let neighbors = self.count_neighbors(x, y);
|
|
|
|
let new_state =
|
|
matches!((old_state, neighbors), (true, 2) | (true, 3) | (false, 3));
|
|
next.set(x, y, new_state);
|
|
}
|
|
}
|
|
next
|
|
}
|
|
|
|
fn count_neighbors(&self, x: usize, y: usize) -> u8 {
|
|
let x = x as i32;
|
|
let y = y as i32;
|
|
let mut count = 0;
|
|
for nx in x - 1..=x + 1 {
|
|
for ny in y - 1..=y + 1 {
|
|
if nx == x && ny == y {
|
|
continue; // the cell itself does not count
|
|
}
|
|
|
|
if nx < 0
|
|
|| ny < 0
|
|
|| nx >= self.field.width() as i32
|
|
|| ny >= self.field.height() as i32
|
|
{
|
|
continue; // pixels outside the grid do not count
|
|
}
|
|
|
|
if !self.field.get(nx as usize, ny as usize) {
|
|
continue; // dead cells do not count
|
|
}
|
|
|
|
count += 1;
|
|
}
|
|
}
|
|
|
|
count
|
|
}
|
|
|
|
fn luma_iteration(&self) -> ByteGrid {
|
|
let mut rng = rand::thread_rng();
|
|
|
|
let min_size = 1;
|
|
let window_x = rng.gen_range(0..TILE_WIDTH as usize - min_size);
|
|
let window_y = rng.gen_range(0..TILE_HEIGHT as usize - min_size);
|
|
|
|
let w = rng.gen_range(min_size..=TILE_WIDTH as usize - window_x);
|
|
let h = rng.gen_range(min_size..=TILE_HEIGHT as usize - window_y);
|
|
|
|
let mut new_luma = self.luma.clone();
|
|
for inner_y in 0..h {
|
|
for inner_x in 0..w {
|
|
let x = window_x + inner_x;
|
|
let y = window_y + inner_y;
|
|
let old_value = self.luma.get(x, y);
|
|
let new_value = i32::clamp(
|
|
old_value as i32 + rng.gen_range(-64..=64),
|
|
u8::MIN as i32,
|
|
u8::MAX as i32,
|
|
) as u8;
|
|
|
|
new_luma.set(x, y, new_value);
|
|
}
|
|
}
|
|
|
|
new_luma
|
|
}
|
|
}
|
|
|
|
impl Default for Game {
|
|
fn default() -> Self {
|
|
Self {
|
|
field: PixelGrid::max_sized(),
|
|
luma: ByteGrid::new(TILE_WIDTH as usize, TILE_HEIGHT as usize),
|
|
}
|
|
}
|
|
}
|