servicepoint-life/src/game.rs
2024-05-18 23:26:34 +02:00

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),
}
}
}