1use super::harmony::rand_u32;
6
7pub struct Life {
8 pub rows: usize,
9 pub cols: usize,
10 grid: Vec<bool>,
11 scratch: Vec<bool>,
12 pub generation: u64,
13}
14
15impl Life {
16 pub fn random(rows: usize, cols: usize, seed: u64, fill: f32) -> Self {
17 let mut s = seed;
18 let n = rows * cols;
19 let mut grid = vec![false; n];
20 let threshold = (fill.clamp(0.0, 1.0) * 1000.0) as u32;
21 for cell in grid.iter_mut() {
22 *cell = rand_u32(&mut s, 1000) < threshold;
23 }
24 Self {
25 rows,
26 cols,
27 grid,
28 scratch: vec![false; n],
29 generation: 0,
30 }
31 }
32
33 #[inline]
34 pub fn alive(&self, r: usize, c: usize) -> bool {
35 self.grid[r * self.cols + c]
36 }
37
38 pub fn step(&mut self) {
40 let rows = self.rows as isize;
41 let cols = self.cols as isize;
42 let cols_us = self.cols;
43 for r in 0..rows {
44 for c in 0..cols {
45 let mut n = 0u8;
46 for dr in -1..=1 {
47 for dc in -1..=1 {
48 if dr == 0 && dc == 0 {
49 continue;
50 }
51 let rr = (r + dr).rem_euclid(rows) as usize;
52 let cc = (c + dc).rem_euclid(cols) as usize;
53 if self.grid[rr * cols_us + cc] {
54 n += 1;
55 }
56 }
57 }
58 let idx = r as usize * cols_us + c as usize;
59 let was = self.grid[idx];
60 let now = matches!((was, n), (true, 2) | (true, 3) | (false, 3));
61 self.scratch[idx] = now;
62 }
63 }
64 std::mem::swap(&mut self.grid, &mut self.scratch);
65 self.generation += 1;
66 }
67
68 pub fn alive_count(&self) -> usize {
69 self.grid.iter().filter(|&&b| b).count()
70 }
71
72 pub fn density(&self) -> f32 {
73 self.alive_count() as f32 / (self.rows * self.cols).max(1) as f32
74 }
75
76 pub fn row_alive_count(&self, r: usize) -> usize {
78 if r >= self.rows {
79 return 0;
80 }
81 let start = r * self.cols;
82 self.grid[start..start + self.cols]
83 .iter()
84 .filter(|&&b| b)
85 .count()
86 }
87
88 pub fn col_alive_count(&self, c: usize) -> usize {
90 if c >= self.cols {
91 return 0;
92 }
93 let mut n = 0;
94 for r in 0..self.rows {
95 if self.grid[r * self.cols + c] {
96 n += 1;
97 }
98 }
99 n
100 }
101
102 pub fn set(&mut self, r: usize, c: usize, alive: bool) {
104 let rr = r % self.rows;
105 let cc = c % self.cols;
106 self.grid[rr * self.cols + cc] = alive;
107 }
108
109 pub fn inject_glider(&mut self, r0: usize, c0: usize) {
112 let cells = [(0, 1), (1, 2), (2, 0), (2, 1), (2, 2)];
113 for (dr, dc) in cells {
114 let r = (r0 + dr) % self.rows;
115 let c = (c0 + dc) % self.cols;
116 self.grid[r * self.cols + c] = true;
117 }
118 }
119
120 pub fn sprinkle(&mut self, seed: &mut u64, count: usize) {
122 for _ in 0..count {
123 let r = rand_u32(seed, self.rows as u32) as usize;
124 let c = rand_u32(seed, self.cols as u32) as usize;
125 self.grid[r * self.cols + c] = true;
126 }
127 }
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133
134 #[test]
135 fn blinker_oscillates() {
136 let mut life = Life::random(5, 5, 0, 0.0);
137 life.grid[2 * 5 + 1] = true;
139 life.grid[2 * 5 + 2] = true;
140 life.grid[2 * 5 + 3] = true;
141 let before = life.alive_count();
142 life.step();
143 let after = life.alive_count();
144 life.step();
145 let back = life.alive_count();
146 assert_eq!(before, 3);
147 assert_eq!(after, 3);
148 assert_eq!(back, 3);
149 }
150
151 #[test]
152 fn empty_stays_empty() {
153 let mut life = Life::random(6, 6, 99, 0.0);
154 life.step();
155 assert_eq!(life.alive_count(), 0);
156 }
157}