life/
life.rs

1use macroquad::prelude::*;
2
3#[derive(Copy, Clone, Debug, PartialEq, Eq)]
4enum CellState {
5    Alive,
6    Dead,
7}
8
9#[macroquad::main("Life")]
10async fn main() {
11    let w = screen_width() as usize;
12    let h = screen_height() as usize;
13
14    let mut cells = vec![CellState::Dead; w * h];
15    let mut buffer = vec![CellState::Dead; w * h];
16
17    let mut image = Image::gen_image_color(w as u16, h as u16, WHITE);
18
19    for cell in cells.iter_mut() {
20        if rand::gen_range(0, 5) == 0 {
21            *cell = CellState::Alive;
22        }
23    }
24    let texture = Texture2D::from_image(&image);
25
26    loop {
27        clear_background(WHITE);
28
29        let w = image.width();
30        let h = image.height();
31
32        for y in 0..h as i32 {
33            for x in 0..w as i32 {
34                let mut neighbors_count = 0;
35
36                for j in -1i32..=1 {
37                    for i in -1i32..=1 {
38                        // out of bounds
39                        if y + j < 0 || y + j >= h as i32 || x + i < 0 || x + i >= w as i32 {
40                            continue;
41                        }
42                        // cell itself
43                        if i == 0 && j == 0 {
44                            continue;
45                        }
46
47                        let neighbor = cells[(y + j) as usize * w + (x + i) as usize];
48                        if neighbor == CellState::Alive {
49                            neighbors_count += 1;
50                        }
51                    }
52                }
53
54                let current_cell = cells[y as usize * w + x as usize];
55                buffer[y as usize * w + x as usize] = match (current_cell, neighbors_count) {
56                    // Rule 1: Any live cell with fewer than two live neighbours
57                    // dies, as if caused by underpopulation.
58                    (CellState::Alive, x) if x < 2 => CellState::Dead,
59                    // Rule 2: Any live cell with two or three live neighbours
60                    // lives on to the next generation.
61                    (CellState::Alive, 2) | (CellState::Alive, 3) => CellState::Alive,
62                    // Rule 3: Any live cell with more than three live
63                    // neighbours dies, as if by overpopulation.
64                    (CellState::Alive, x) if x > 3 => CellState::Dead,
65                    // Rule 4: Any dead cell with exactly three live neighbours
66                    // becomes a live cell, as if by reproduction.
67                    (CellState::Dead, 3) => CellState::Alive,
68                    // All other cells remain in the same state.
69                    (otherwise, _) => otherwise,
70                };
71            }
72        }
73
74        for i in 0..buffer.len() {
75            cells[i] = buffer[i];
76
77            image.set_pixel(
78                (i % w) as u32,
79                (i / w) as u32,
80                match buffer[i as usize] {
81                    CellState::Alive => BLACK,
82                    CellState::Dead => WHITE,
83                },
84            );
85        }
86
87        texture.update(&image);
88
89        draw_texture(&texture, 0., 0., WHITE);
90
91        next_frame().await
92    }
93}