Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 19 additions & 9 deletions examples/tui/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ impl App {
KeyCode::Char('r') => self.run_simulation(),
KeyCode::Char('s') => self.stop_simulation(),
KeyCode::Char('n') => self.cycle(),
KeyCode::Char('p') => self.perturb(),
KeyCode::Char('?') => self.random_grid(),
_ => {}
}
Expand All @@ -96,6 +97,10 @@ impl App {
self.grid.update_states();
self.cycles = 0;
}

fn perturb(&mut self) {
self.grid.perturb_grid(0.05);
}
}

impl Widget for &App {
Expand All @@ -112,6 +117,8 @@ impl Widget for &App {
"<n>".blue().bold(),
" Regenerate".into(),
"<?>".blue().bold(),
" Perturb".into(),
"<p>".blue().bold(),
" Population: ".into(),
format!("{}", self.population).red().bold(),
" Cycles: ".into(),
Expand Down Expand Up @@ -146,20 +153,21 @@ mod tests {
#[test]
fn render() {
let app = App::default();
let mut buf = Buffer::empty(Rect::new(0, 0, 100, 4));
let mut buf = Buffer::empty(Rect::new(0, 0, 111, 4));

app.render(buf.area, &mut buf);
let mut expected = Buffer::with_lines(vec![
"┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Game of Life ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓",
"┃ ┃",
"┃ ┃",
"┗━━━━━━━━━ Quit <Q> Run<r> Stop<s> Single Cycle<n> Regenerate<?> Population: 0 Cycles: 0 ━━━━━━━━━┛",
"┏━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ Game of Life ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓",
"┃ ┃",
"┃ ┃",
"┗━━━━━━━━━ Quit <Q> Run<r> Stop<s> Single Cycle<n> Regenerate<?> Perturb<p> Population: 0 Cycles: 0 ━━━━━━━━━┛",
]);
let title_style = Style::new().bold();
let counter_style = Style::new().red().bold();
let key_style = Style::new().blue().bold();

// Game of Life
expected.set_style(Rect::new(43, 0, 14, 1), title_style);
expected.set_style(Rect::new(48, 0, 14, 1), title_style);
// <Q>
expected.set_style(Rect::new(16, 3, 4, 1), key_style);
// <r>
Expand All @@ -168,12 +176,14 @@ mod tests {
expected.set_style(Rect::new(32, 3, 3, 1), key_style);
//<n>
expected.set_style(Rect::new(48, 3, 3, 1), key_style);
//<?>
//<p>
expected.set_style(Rect::new(62, 3, 3, 1), key_style);
//<?>
expected.set_style(Rect::new(73, 3, 3, 1), key_style);
// 0
expected.set_style(Rect::new(78, 3, 1, 1), counter_style);
expected.set_style(Rect::new(89, 3, 1, 1), counter_style);
// 0
expected.set_style(Rect::new(88, 3, 2, 1), counter_style);
expected.set_style(Rect::new(99, 3, 2, 1), counter_style);
assert_eq!(buf, expected);
}

Expand Down
72 changes: 72 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,22 @@ impl Grid<CellState> {
}
NeighbourState { alive, dead }
}
/// Randomly flips one cell
pub fn rand_flip(&mut self) {
let i = fastrand::usize(0..self.cells.len());
self.cells[i] = match self.cells[i] {
CellState::Alive(_) => CellState::Dead(self.dead_glyph),
CellState::Dead(_) => CellState::Alive(self.alive_glyph),
};
}
/// Randomly flips p*cell.len() cells.
/// Can be use to keep the simulation interesting.
pub fn perturb_grid(&mut self, p: f32) {
let p = p.clamp(0.0, 1.0);
for _ in 0..((p * self.cells.len() as f32).floor() as i32) {
self.rand_flip();
}
}
}

impl Default for Grid<CellState> {
Expand Down Expand Up @@ -396,4 +412,60 @@ mod tests {
.collect();
assert_eq!(unexpected_states.len(), 0);
}

#[test]
fn test_rand_flip() {
// Flip the only cell
let mut g = Grid::new_empty(1, 1);
g.rand_flip();
assert!(
g.try_get(Point { x: 0, y: 0 })
== Some(&CellState::Alive(g.alive_glyph))
);

// Flipping one cell should change the population by 1
let mut g = Grid::new_random(2, 1);
let flip0 = g.calculate_population();
g.rand_flip();
let flip1 = g.calculate_population();
assert!(
flip0.saturating_sub(flip1) == 1
|| flip1.saturating_sub(flip0) == 1
);
g.rand_flip();
let flip2 = g.calculate_population();
assert!(
flip2.saturating_sub(flip1) == 1
|| flip1.saturating_sub(flip2) == 1
);
}

#[test]
fn test_perturb_grid() {
// Flip the only cell
let mut g = Grid::new_empty(1, 1);
g.perturb_grid(1.0);
assert!(
g.try_get(Point { x: 0, y: 0 })
== Some(&CellState::Alive(g.alive_glyph))
);

// Flip one cell
let mut g = Grid::new_empty(10, 10);
let perturb0 = g.calculate_population();
g.perturb_grid(0.01);
let perturb1 = g.calculate_population();
assert!(
perturb0.saturating_sub(perturb1) == 1
|| perturb1.saturating_sub(perturb0) == 1
);

// Flip one cell
g.perturb_grid(0.01);
let perturb2 = g.calculate_population();
assert!(
perturb1.saturating_sub(perturb2) == 1
|| perturb2.saturating_sub(perturb1) == 1
);
}
}
Loading