summaryrefslogtreecommitdiffstats
path: root/examples/game_of_life
diff options
context:
space:
mode:
authorLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-07-10 04:14:21 +0200
committerLibravatar Héctor Ramón Jiménez <hector0193@gmail.com>2020-07-10 04:14:21 +0200
commitb64e0ea5e31e718e435b24244119f59f7128bc27 (patch)
treeb63acb2ca9c1ff4838430b75121e83cea962c34d /examples/game_of_life
parent73b8ae8e5e7f57c608c775272a2980995ab22bb3 (diff)
downloadiced-b64e0ea5e31e718e435b24244119f59f7128bc27.tar.gz
iced-b64e0ea5e31e718e435b24244119f59f7128bc27.tar.bz2
iced-b64e0ea5e31e718e435b24244119f59f7128bc27.zip
Add `Preset` selector to `game_of_life` example
Diffstat (limited to 'examples/game_of_life')
-rw-r--r--examples/game_of_life/src/main.rs79
-rw-r--r--examples/game_of_life/src/preset.rs142
2 files changed, 209 insertions, 12 deletions
diff --git a/examples/game_of_life/src/main.rs b/examples/game_of_life/src/main.rs
index 080d55c0..4663ae72 100644
--- a/examples/game_of_life/src/main.rs
+++ b/examples/game_of_life/src/main.rs
@@ -1,15 +1,19 @@
//! This example showcases an interactive version of the Game of Life, invented
//! by John Conway. It leverages a `Canvas` together with other widgets.
+mod preset;
mod style;
use grid::Grid;
+use iced::button::{self, Button};
+use iced::executor;
+use iced::pick_list::{self, PickList};
+use iced::slider::{self, Slider};
+use iced::time;
use iced::{
- button::{self, Button},
- executor,
- slider::{self, Slider},
- time, Align, Application, Checkbox, Column, Command, Container, Element,
- Length, Row, Settings, Subscription, Text,
+ Align, Application, Checkbox, Column, Command, Container, Element, Length,
+ Row, Settings, Subscription, Text,
};
+use preset::Preset;
use std::time::{Duration, Instant};
pub fn main() {
@@ -38,6 +42,7 @@ enum Message {
Next,
Clear,
SpeedChanged(f32),
+ PresetPicked(Preset),
}
impl Application for GameOfLife {
@@ -48,7 +53,7 @@ impl Application for GameOfLife {
fn new(_flags: ()) -> (Self, Command<Message>) {
(
Self {
- speed: 1,
+ speed: 5,
..Self::default()
},
Command::none(),
@@ -93,6 +98,9 @@ impl Application for GameOfLife {
self.speed = speed.round() as usize;
}
}
+ Message::PresetPicked(new_preset) => {
+ self.grid = Grid::from_preset(new_preset);
+ }
}
Command::none()
@@ -113,6 +121,7 @@ impl Application for GameOfLife {
self.is_playing,
self.grid.are_lines_visible(),
selected_speed,
+ self.grid.preset(),
);
let content = Column::new()
@@ -128,6 +137,7 @@ impl Application for GameOfLife {
}
mod grid {
+ use crate::Preset;
use iced::{
canvas::{
self, Cache, Canvas, Cursor, Event, Frame, Geometry, Path, Text,
@@ -142,6 +152,7 @@ mod grid {
pub struct Grid {
state: State,
+ preset: Preset,
interaction: Interaction,
life_cache: Cache,
grid_cache: Cache,
@@ -171,8 +182,24 @@ mod grid {
impl Default for Grid {
fn default() -> Self {
+ Self::from_preset(Preset::default())
+ }
+ }
+
+ impl Grid {
+ const MIN_SCALING: f32 = 0.1;
+ const MAX_SCALING: f32 = 2.0;
+
+ pub fn from_preset(preset: Preset) -> Self {
Self {
- state: State::default(),
+ state: State::with_life(
+ preset
+ .life()
+ .into_iter()
+ .map(|(i, j)| Cell { i, j })
+ .collect(),
+ ),
+ preset,
interaction: Interaction::None,
life_cache: Cache::default(),
grid_cache: Cache::default(),
@@ -184,11 +211,6 @@ mod grid {
version: 0,
}
}
- }
-
- impl Grid {
- const MIN_SCALING: f32 = 0.1;
- const MAX_SCALING: f32 = 2.0;
pub fn tick(
&mut self,
@@ -217,10 +239,14 @@ mod grid {
Message::Populate(cell) => {
self.state.populate(cell);
self.life_cache.clear();
+
+ self.preset = Preset::Custom;
}
Message::Unpopulate(cell) => {
self.state.unpopulate(&cell);
self.life_cache.clear();
+
+ self.preset = Preset::Custom;
}
Message::Ticked {
result: Ok(life),
@@ -230,6 +256,7 @@ mod grid {
self.state.update(life);
self.life_cache.clear();
+ self.version += 1;
self.last_tick_duration = tick_duration;
}
Message::Ticked {
@@ -250,11 +277,16 @@ mod grid {
pub fn clear(&mut self) {
self.state = State::default();
+ self.preset = Preset::Custom;
self.version += 1;
self.life_cache.clear();
}
+ pub fn preset(&self) -> Preset {
+ self.preset
+ }
+
pub fn toggle_lines(&mut self, enabled: bool) {
self.show_lines = enabled;
}
@@ -533,6 +565,13 @@ mod grid {
}
impl State {
+ pub fn with_life(life: Life) -> Self {
+ Self {
+ life,
+ ..Self::default()
+ }
+ }
+
fn cell_count(&self) -> usize {
self.life.len() + self.births.len()
}
@@ -647,6 +686,14 @@ mod grid {
}
}
+ impl std::iter::FromIterator<Cell> for Life {
+ fn from_iter<I: IntoIterator<Item = Cell>>(iter: I) -> Self {
+ Life {
+ cells: iter.into_iter().collect(),
+ }
+ }
+ }
+
impl std::fmt::Debug for Life {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Life")
@@ -741,6 +788,7 @@ struct Controls {
next_button: button::State,
clear_button: button::State,
speed_slider: slider::State,
+ preset_list: pick_list::State,
}
impl Controls {
@@ -749,6 +797,7 @@ impl Controls {
is_playing: bool,
is_grid_enabled: bool,
speed: usize,
+ preset: Preset,
) -> Element<'a, Message> {
let playback_controls = Row::new()
.spacing(10)
@@ -793,6 +842,12 @@ impl Controls {
.spacing(5)
.text_size(16),
)
+ .push(PickList::new(
+ &mut self.preset_list,
+ preset::ALL,
+ Some(preset),
+ Message::PresetPicked,
+ ))
.push(
Button::new(&mut self.clear_button, Text::new("Clear"))
.on_press(Message::Clear)
diff --git a/examples/game_of_life/src/preset.rs b/examples/game_of_life/src/preset.rs
new file mode 100644
index 00000000..1a471141
--- /dev/null
+++ b/examples/game_of_life/src/preset.rs
@@ -0,0 +1,142 @@
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Preset {
+ Custom,
+ XKCD,
+ Glider,
+ SmallExploder,
+ Exploder,
+ TenCellRow,
+ LightweightSpaceship,
+ Tumbler,
+ Acorn,
+ GliderGun,
+}
+
+pub static ALL: &[Preset] = &[
+ Preset::Custom,
+ Preset::XKCD,
+ Preset::Glider,
+ Preset::SmallExploder,
+ Preset::Exploder,
+ Preset::TenCellRow,
+ Preset::LightweightSpaceship,
+ Preset::Tumbler,
+ Preset::Acorn,
+ Preset::GliderGun,
+];
+
+impl Preset {
+ pub fn life(self) -> Vec<(isize, isize)> {
+ #[rustfmt::skip]
+ let cells = match self {
+ Preset::Custom => vec![],
+ Preset::XKCD => vec![
+ " xxx ",
+ " x x ",
+ " x x ",
+ " x ",
+ "x xxx ",
+ " x x x ",
+ " x x",
+ " x x ",
+ " x x ",
+ ],
+ Preset::Glider => vec![
+ " x ",
+ " x",
+ "xxx"
+ ],
+ Preset::SmallExploder => vec![
+ " x ",
+ "xxx",
+ "x x",
+ " x ",
+ ],
+ Preset::Exploder => vec![
+ "x x x",
+ "x x",
+ "x x",
+ "x x",
+ "x x x",
+ ],
+ Preset::TenCellRow => vec![
+ "xxxxxxxxxx",
+ ],
+ Preset::LightweightSpaceship => vec![
+ " xxxxx",
+ "x x",
+ " x",
+ "x x ",
+ ],
+ Preset::Tumbler => vec![
+ " xx xx ",
+ " xx xx ",
+ " x x ",
+ "x x x x",
+ "x x x x",
+ "xx xx",
+ ],
+ Preset::Acorn => vec![
+ " x ",
+ " x ",
+ "xx xxx",
+ ],
+ Preset::GliderGun => vec![
+ " x ",
+ " x x ",
+ " xx xx xx",
+ " x x xx xx",
+ "xx x x xx ",
+ "xx x x xx x x ",
+ " x x x ",
+ " x x ",
+ " xx ",
+ ]
+ };
+
+ let start_row = -(cells.len() as isize / 2);
+
+ cells
+ .into_iter()
+ .enumerate()
+ .flat_map(|(i, cells)| {
+ let start_column = -(cells.len() as isize / 2);
+
+ cells
+ .chars()
+ .enumerate()
+ .filter(|(_, c)| !c.is_whitespace())
+ .map(move |(j, _)| {
+ (start_row + i as isize, start_column + j as isize)
+ })
+ })
+ .collect()
+ }
+}
+
+impl Default for Preset {
+ fn default() -> Preset {
+ Preset::XKCD
+ }
+}
+
+impl std::fmt::Display for Preset {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(
+ f,
+ "{}",
+ match self {
+ Preset::Custom => "Custom",
+ Preset::XKCD => "xkcd #2293",
+ Preset::Glider => "Glider",
+ Preset::SmallExploder => "Small Exploder",
+ Preset::Exploder => "Exploder",
+ Preset::TenCellRow => "10 Cell Row",
+ Preset::LightweightSpaceship => "Lightweight spaceship",
+ Preset::Tumbler => "Tumbler",
+ Preset::Acorn => "Acorn",
+ Preset::GliderGun => "Gosper Glider Gun",
+ }
+ )
+ }
+}