-
Notifications
You must be signed in to change notification settings - Fork 22
/
Copy pathgame_of_life.rs
117 lines (95 loc) · 3.13 KB
/
game_of_life.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
use game_loop::game_loop;
fn main() {
let mut game = GameOfLife::new(12, 12);
// Make some of the cells alive.
game.set(5, 5);
game.set(5, 6);
game.set(5, 7);
game.set(6, 6);
// Run the game loop with 2 updates per second.
let g = game_loop(game, 2, 1.0, |g| {
g.game.update();
}, |g| {
// Pass the blending factor (even though this example doesn't use it).
g.game.render(g.blending_factor());
// Exit after 10 seconds.
if g.running_time() > 10.0 {
g.exit();
}
});
// Use the 'g' variable to query the game loop after it finishes.
println!("Exiting after {} seconds", g.running_time());
println!("");
println!("Last frame time: {}", g.last_frame_time());
println!("Number of updates: {}", g.number_of_updates());
println!("Number of renders: {}", g.number_of_renders());
}
// A quick and dirty implementation of Conway's Game of Life.
struct GameOfLife {
board: Board,
width: usize,
height: usize,
}
type Board = Vec<Vec<bool>>;
impl GameOfLife {
fn new(width: usize, height: usize) -> Self {
let board = vec![vec![false; width]; height];
Self { board, width, height }
}
fn set(&mut self, x: usize, y: usize) {
self.board[y][x] = true;
}
fn update(&mut self) {
self.board = self.next_board();
}
fn next_board(&self) -> Board {
(0..self.height).map(|y| {
(0..self.width).map(|x| {
self.next_cell(x, y)
}).collect()
}).collect()
}
fn next_cell(&self, x: usize, y: usize) -> bool {
let cell = self.board[y][x];
let count = self.alive_neighbors(x as isize, y as isize);
count == 3 || (cell && count == 2)
}
fn alive_neighbors(&self, x: isize, y: isize) -> usize {
self.neighbors(x, y).iter().filter(|b| **b).count()
}
fn neighbors(&self, x: isize, y: isize) -> [bool; 8] {
[
self.neighbor(x - 1, y - 1), // top left
self.neighbor(x , y - 1), // above
self.neighbor(x + 1, y - 1), // top right
self.neighbor(x - 1, y ), // left
self.neighbor(x + 1, y ), // right
self.neighbor(x - 1, y + 1), // bottom left
self.neighbor(x , y + 1), // below
self.neighbor(x + 1, y + 1), // bottom right
]
}
fn neighbor(&self, x: isize, y: isize) -> bool {
if x < 0 { return false; }
if y < 0 { return false; }
*self.board
.get(y as usize).unwrap_or(&vec![])
.get(x as usize).unwrap_or(&false)
}
fn render(&self, _blending_factor: f64) {
print!("{}[2J", 27 as char); // clear terminal
for row in self.board.iter() {
for cell in row {
if *cell {
print!("X");
} else {
print!("_");
}
}
println!();
}
println!();
// Limit rendering to a maximum of 10 frames per second.
std::thread::sleep(std::time::Duration::from_millis(100));
}
}