servicepoint-life/src/game.rs
2025-05-02 15:53:39 +02:00

61 lines
1.8 KiB
Rust

use servicepoint::{Grid, Value, ValueGrid};
use crate::rules::Rules;
pub(crate) struct Game<T: Value>
{
pub field: ValueGrid<T>,
pub rules: Rules<T>,
}
impl<T: Value> Game<T>
{
pub fn step(&mut self) {
self.field = self.field_iteration();
}
fn field_iteration(&self) -> ValueGrid<T> {
let mut next = ValueGrid::new(self.field.width(), self.field.height());
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 = (self.rules.next_state)(old_state, neighbors);
next.set(x, y, new_state);
}
}
next
}
fn count_neighbors(&self, x: usize, y: usize) -> i32 {
let x = x as i32;
let y = y as i32;
let mut count = 0;
let kernel = &self.rules.kernel;
for (kernel_y, kernel_row) in kernel.iter().enumerate() {
let offset_y = kernel_y as i32 - 1;
for (kernel_x, kernel_value) in kernel_row.iter().enumerate() {
let offset_x = kernel_x as i32 - 1;
let neighbor_x = x + offset_x;
let neighbor_y = y + offset_y;
if neighbor_x < 0
|| neighbor_y < 0
|| neighbor_x >= self.field.width() as i32
|| neighbor_y >= self.field.height() as i32
{
continue; // pixels outside the grid do not count
}
let neighbor_state = self.field.get(neighbor_x as usize, neighbor_y as usize);
count += (self.rules.count_neighbor)(neighbor_state, *kernel_value);
}
}
count
}
}