diff --git a/src/cell.rs b/src/cell.rs index 7bd8918..5e29515 100644 --- a/src/cell.rs +++ b/src/cell.rs @@ -6,6 +6,7 @@ use crate::K2; use crate::Q; use crate::WIDTH; +// Class to store information about each cell #[derive(PartialEq)] pub struct Cell { pub x: u32, @@ -13,6 +14,7 @@ pub struct Cell { pub state: u32, } +// Type Enumerator to keep track of different state operations #[derive(PartialEq)] enum StateOp { Types, @@ -20,28 +22,34 @@ enum StateOp { } impl Cell { + // Cell method to count neighbors depending on state operation fn neighbor_count(&self, grid: &Vec>, operation: StateOp) -> (u32, u32) { let mut infected: u32 = 0; let mut states: u32 = 0; let mut sum: u32 = 0; let mut ill: u32 = 0; + // Loop through neighbors for j in -1..=1 { for i in -1..=1 { + // Ignore self onlz if operation is generic 'types' if i == 0 && j == 0 && operation == StateOp::Types { continue; } + // Get cell at position with wrap-around let nx = (self.x as i32 + i + WIDTH as i32) % WIDTH as i32; let ny = (self.y as i32 + j + HEIGHT as i32) % HEIGHT as i32; let next = &grid[ny as usize][nx as usize]; let state = next.state; + // Count ill and infected cells if operation == StateOp::Types { if state > 1 && state < Q - 1 { infected += 1; } else if state == Q - 1 { ill += 1; } + // Count and sum states around cell } else { sum += state; if state == 1 && next != self { @@ -51,6 +59,7 @@ impl Cell { } } + // Return results based on operation type if operation == StateOp::Types { return (infected, ill); } else { @@ -59,38 +68,47 @@ impl Cell { } } +// Initialize grid with random states or if option is provided, with previous states pub fn init_grid(option: Option<&Vec>>) -> Vec> { let mut grid: Vec> = Vec::new(); for j in 0..HEIGHT { let mut row: Vec = Vec::new(); for i in 0..WIDTH { + // Generate random state let mut value = rand::random::() % Q; if let Some(g) = option { + // Extract previous state value = g[j as usize][i as usize].state; } + // Add cell row.push(Cell { x: i, y: j, state: value, }); } + // Add row grid.push(row); } grid } +// Map number from one range to another fn map_num(n: usize, s: usize, e: usize, a: usize, b: usize) -> usize { (a as f64 + (n as f64 - s as f64) * (b as f64 - a as f64) / (e as f64 - s as f64)) as usize } +// Display grid in console pub fn display_grid(grid: &Vec>) { for j in 0..HEIGHT { for i in 0..WIDTH { + // Get cell in grid let x = i as usize; let y = j as usize; let state = grid[y][x].state as usize; + // Print cell to console let index = map_num(state, 0, Q as usize, 0, BRIGHTNESS.len()); print!("{}", BRIGHTNESS.chars().nth(index).unwrap()); } @@ -98,26 +116,33 @@ pub fn display_grid(grid: &Vec>) { } } +// Calculate next generation pub fn update_grid(grid: &mut Vec>) { + // Initialize new generation by copying old let mut new_gen = init_grid(Some(grid)); for j in 0..HEIGHT { for i in 0..WIDTH { let x = i as usize; let y = j as usize; + // Get cell in both grids let current = &grid[y][x]; let next = &mut new_gen[y][x]; + // Reset at end if current.state == Q - 1 { next.state = 0; + // Calculate based on neighbors } else if current.state == 0 { let (inf, ill) = current.neighbor_count(&grid, StateOp::Types); next.state = inf / K1 + ill / K2; + // Calculate based on states } else { let (sum, states) = current.neighbor_count(&grid, StateOp::States); next.state = sum / (9 - states) + G; } + // Clamp state to maximum if next.state >= Q { next.state = Q - 1; } diff --git a/src/main.rs b/src/main.rs index b608122..66bffaf 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,8 +1,10 @@ +// Display settings pub const BRIGHTNESS: &str = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. "; pub const HEIGHT: u32 = 25; // Max: 35 pub const WIDTH: u32 = 25; // Max: 145 pub const FPS: u32 = 10; +// Game settings pub const K1: u32 = 2; pub const K2: u32 = 3; pub const G: u32 = 35; @@ -14,11 +16,14 @@ use cell::*; use std::{thread, time::Duration}; fn main() { + // Initialize grid randomly let mut grid = init_grid(None); loop { + // Display current generation print!("{esc}[2J{esc}[1;1H", esc = 27 as char); display_grid(&grid); + // Calculate next generation and wait update_grid(&mut grid); thread::sleep(Duration::from_millis(1000 / (FPS as u64))); }