added comments to code

This commit is contained in:
Baipyrus 2024-05-07 13:44:13 +02:00
parent 95467cb94f
commit 4808e7c78a
2 changed files with 30 additions and 0 deletions

View File

@ -6,6 +6,7 @@ use crate::K2;
use crate::Q; use crate::Q;
use crate::WIDTH; use crate::WIDTH;
// Class to store information about each cell
#[derive(PartialEq)] #[derive(PartialEq)]
pub struct Cell { pub struct Cell {
pub x: u32, pub x: u32,
@ -13,6 +14,7 @@ pub struct Cell {
pub state: u32, pub state: u32,
} }
// Type Enumerator to keep track of different state operations
#[derive(PartialEq)] #[derive(PartialEq)]
enum StateOp { enum StateOp {
Types, Types,
@ -20,28 +22,34 @@ enum StateOp {
} }
impl Cell { impl Cell {
// Cell method to count neighbors depending on state operation
fn neighbor_count(&self, grid: &Vec<Vec<Cell>>, operation: StateOp) -> (u32, u32) { fn neighbor_count(&self, grid: &Vec<Vec<Cell>>, operation: StateOp) -> (u32, u32) {
let mut infected: u32 = 0; let mut infected: u32 = 0;
let mut states: u32 = 0; let mut states: u32 = 0;
let mut sum: u32 = 0; let mut sum: u32 = 0;
let mut ill: u32 = 0; let mut ill: u32 = 0;
// Loop through neighbors
for j in -1..=1 { for j in -1..=1 {
for i in -1..=1 { for i in -1..=1 {
// Ignore self onlz if operation is generic 'types'
if i == 0 && j == 0 && operation == StateOp::Types { if i == 0 && j == 0 && operation == StateOp::Types {
continue; continue;
} }
// Get cell at position with wrap-around
let nx = (self.x as i32 + i + WIDTH as i32) % WIDTH as i32; 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 ny = (self.y as i32 + j + HEIGHT as i32) % HEIGHT as i32;
let next = &grid[ny as usize][nx as usize]; let next = &grid[ny as usize][nx as usize];
let state = next.state; let state = next.state;
// Count ill and infected cells
if operation == StateOp::Types { if operation == StateOp::Types {
if state > 1 && state < Q - 1 { if state > 1 && state < Q - 1 {
infected += 1; infected += 1;
} else if state == Q - 1 { } else if state == Q - 1 {
ill += 1; ill += 1;
} }
// Count and sum states around cell
} else { } else {
sum += state; sum += state;
if state == 1 && next != self { if state == 1 && next != self {
@ -51,6 +59,7 @@ impl Cell {
} }
} }
// Return results based on operation type
if operation == StateOp::Types { if operation == StateOp::Types {
return (infected, ill); return (infected, ill);
} else { } 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<Cell>>>) -> Vec<Vec<Cell>> { pub fn init_grid(option: Option<&Vec<Vec<Cell>>>) -> Vec<Vec<Cell>> {
let mut grid: Vec<Vec<Cell>> = Vec::new(); let mut grid: Vec<Vec<Cell>> = Vec::new();
for j in 0..HEIGHT { for j in 0..HEIGHT {
let mut row: Vec<Cell> = Vec::new(); let mut row: Vec<Cell> = Vec::new();
for i in 0..WIDTH { for i in 0..WIDTH {
// Generate random state
let mut value = rand::random::<u32>() % Q; let mut value = rand::random::<u32>() % Q;
if let Some(g) = option { if let Some(g) = option {
// Extract previous state
value = g[j as usize][i as usize].state; value = g[j as usize][i as usize].state;
} }
// Add cell
row.push(Cell { row.push(Cell {
x: i, x: i,
y: j, y: j,
state: value, state: value,
}); });
} }
// Add row
grid.push(row); grid.push(row);
} }
grid grid
} }
// Map number from one range to another
fn map_num(n: usize, s: usize, e: usize, a: usize, b: usize) -> usize { 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 (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<Vec<Cell>>) { pub fn display_grid(grid: &Vec<Vec<Cell>>) {
for j in 0..HEIGHT { for j in 0..HEIGHT {
for i in 0..WIDTH { for i in 0..WIDTH {
// Get cell in grid
let x = i as usize; let x = i as usize;
let y = j as usize; let y = j as usize;
let state = grid[y][x].state 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()); let index = map_num(state, 0, Q as usize, 0, BRIGHTNESS.len());
print!("{}", BRIGHTNESS.chars().nth(index).unwrap()); print!("{}", BRIGHTNESS.chars().nth(index).unwrap());
} }
@ -98,26 +116,33 @@ pub fn display_grid(grid: &Vec<Vec<Cell>>) {
} }
} }
// Calculate next generation
pub fn update_grid(grid: &mut Vec<Vec<Cell>>) { pub fn update_grid(grid: &mut Vec<Vec<Cell>>) {
// Initialize new generation by copying old
let mut new_gen = init_grid(Some(grid)); let mut new_gen = init_grid(Some(grid));
for j in 0..HEIGHT { for j in 0..HEIGHT {
for i in 0..WIDTH { for i in 0..WIDTH {
let x = i as usize; let x = i as usize;
let y = j as usize; let y = j as usize;
// Get cell in both grids
let current = &grid[y][x]; let current = &grid[y][x];
let next = &mut new_gen[y][x]; let next = &mut new_gen[y][x];
// Reset at end
if current.state == Q - 1 { if current.state == Q - 1 {
next.state = 0; next.state = 0;
// Calculate based on neighbors
} else if current.state == 0 { } else if current.state == 0 {
let (inf, ill) = current.neighbor_count(&grid, StateOp::Types); let (inf, ill) = current.neighbor_count(&grid, StateOp::Types);
next.state = inf / K1 + ill / K2; next.state = inf / K1 + ill / K2;
// Calculate based on states
} else { } else {
let (sum, states) = current.neighbor_count(&grid, StateOp::States); let (sum, states) = current.neighbor_count(&grid, StateOp::States);
next.state = sum / (9 - states) + G; next.state = sum / (9 - states) + G;
} }
// Clamp state to maximum
if next.state >= Q { if next.state >= Q {
next.state = Q - 1; next.state = Q - 1;
} }

View File

@ -1,8 +1,10 @@
// Display settings
pub const BRIGHTNESS: &str = pub const BRIGHTNESS: &str =
"$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. "; "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\\|()1{}[]?-_+~<>i!lI;:,\"^`'. ";
pub const HEIGHT: u32 = 25; // Max: 35 pub const HEIGHT: u32 = 25; // Max: 35
pub const WIDTH: u32 = 25; // Max: 145 pub const WIDTH: u32 = 25; // Max: 145
pub const FPS: u32 = 10; pub const FPS: u32 = 10;
// Game settings
pub const K1: u32 = 2; pub const K1: u32 = 2;
pub const K2: u32 = 3; pub const K2: u32 = 3;
pub const G: u32 = 35; pub const G: u32 = 35;
@ -14,11 +16,14 @@ use cell::*;
use std::{thread, time::Duration}; use std::{thread, time::Duration};
fn main() { fn main() {
// Initialize grid randomly
let mut grid = init_grid(None); let mut grid = init_grid(None);
loop { loop {
// Display current generation
print!("{esc}[2J{esc}[1;1H", esc = 27 as char); print!("{esc}[2J{esc}[1;1H", esc = 27 as char);
display_grid(&grid); display_grid(&grid);
// Calculate next generation and wait
update_grid(&mut grid); update_grid(&mut grid);
thread::sleep(Duration::from_millis(1000 / (FPS as u64))); thread::sleep(Duration::from_millis(1000 / (FPS as u64)));
} }