Display some statistics in game_of_life
This commit is contained in:
parent
916a1bfc70
commit
0025b8c3f8
2 changed files with 119 additions and 23 deletions
|
|
@ -26,6 +26,8 @@ struct GameOfLife {
|
||||||
next_button: button::State,
|
next_button: button::State,
|
||||||
clear_button: button::State,
|
clear_button: button::State,
|
||||||
speed_slider: slider::State,
|
speed_slider: slider::State,
|
||||||
|
tick_duration: Duration,
|
||||||
|
tick_amount: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
|
|
@ -71,7 +73,12 @@ impl Application for GameOfLife {
|
||||||
fn update(&mut self, message: Message) -> Command<Message> {
|
fn update(&mut self, message: Message) -> Command<Message> {
|
||||||
match message {
|
match message {
|
||||||
Message::Grid(message) => {
|
Message::Grid(message) => {
|
||||||
self.grid.update(message);
|
if let Some((tick_duration, tick_amount)) =
|
||||||
|
self.grid.update(message)
|
||||||
|
{
|
||||||
|
self.tick_duration = tick_duration;
|
||||||
|
self.tick_amount = tick_amount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Message::Tick(_) | Message::Next => match &mut self.state {
|
Message::Tick(_) | Message::Next => match &mut self.state {
|
||||||
State::Paused => {
|
State::Paused => {
|
||||||
|
|
@ -86,7 +93,7 @@ impl Application for GameOfLife {
|
||||||
let needed_ticks =
|
let needed_ticks =
|
||||||
(self.speed as f32 * seconds_elapsed).ceil() as usize;
|
(self.speed as f32 * seconds_elapsed).ceil() as usize;
|
||||||
|
|
||||||
if let Some(task) = self.grid.tick(needed_ticks) {
|
if let Some(task) = self.grid.tick(needed_ticks.max(1)) {
|
||||||
*last_tick = Instant::now();
|
*last_tick = Instant::now();
|
||||||
|
|
||||||
if let Some(speed) = self.next_speed.take() {
|
if let Some(speed) = self.next_speed.take() {
|
||||||
|
|
@ -154,33 +161,49 @@ impl Application for GameOfLife {
|
||||||
|
|
||||||
let selected_speed = self.next_speed.unwrap_or(self.speed);
|
let selected_speed = self.next_speed.unwrap_or(self.speed);
|
||||||
let speed_controls = Row::new()
|
let speed_controls = Row::new()
|
||||||
|
.width(Length::Fill)
|
||||||
|
.align_items(Align::Center)
|
||||||
.spacing(10)
|
.spacing(10)
|
||||||
.push(
|
.push(
|
||||||
Slider::new(
|
Slider::new(
|
||||||
&mut self.speed_slider,
|
&mut self.speed_slider,
|
||||||
1.0..=100.0,
|
1.0..=1000.0,
|
||||||
selected_speed as f32,
|
selected_speed as f32,
|
||||||
Message::SpeedChanged,
|
Message::SpeedChanged,
|
||||||
)
|
)
|
||||||
.width(Length::Units(200))
|
|
||||||
.style(style::Slider),
|
.style(style::Slider),
|
||||||
)
|
)
|
||||||
.push(Text::new(format!("x{}", selected_speed)).size(16))
|
.push(Text::new(format!("x{}", selected_speed)).size(16));
|
||||||
.align_items(Align::Center);
|
|
||||||
|
let stats = Column::new()
|
||||||
|
.width(Length::Units(150))
|
||||||
|
.align_items(Align::Center)
|
||||||
|
.spacing(2)
|
||||||
|
.push(
|
||||||
|
Text::new(format!("{} cells", self.grid.cell_count())).size(14),
|
||||||
|
)
|
||||||
|
.push(
|
||||||
|
Text::new(format!(
|
||||||
|
"{:?} ({})",
|
||||||
|
self.tick_duration, self.tick_amount
|
||||||
|
))
|
||||||
|
.size(14),
|
||||||
|
);
|
||||||
|
|
||||||
let controls = Row::new()
|
let controls = Row::new()
|
||||||
.padding(10)
|
.padding(10)
|
||||||
.spacing(20)
|
.spacing(20)
|
||||||
|
.align_items(Align::Center)
|
||||||
.push(playback_controls)
|
.push(playback_controls)
|
||||||
.push(speed_controls)
|
.push(speed_controls)
|
||||||
|
.push(stats)
|
||||||
.push(
|
.push(
|
||||||
Button::new(&mut self.clear_button, Text::new("Clear"))
|
Button::new(&mut self.clear_button, Text::new("Clear"))
|
||||||
.on_press(Message::Clear)
|
.on_press(Message::Clear)
|
||||||
.style(style::Button),
|
.style(style::Clear),
|
||||||
);
|
);
|
||||||
|
|
||||||
let content = Column::new()
|
let content = Column::new()
|
||||||
.align_items(Align::Center)
|
|
||||||
.push(self.grid.view().map(Message::Grid))
|
.push(self.grid.view().map(Message::Grid))
|
||||||
.push(controls);
|
.push(controls);
|
||||||
|
|
||||||
|
|
@ -199,6 +222,7 @@ mod grid {
|
||||||
};
|
};
|
||||||
use rustc_hash::{FxHashMap, FxHashSet};
|
use rustc_hash::{FxHashMap, FxHashSet};
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
pub struct Grid {
|
pub struct Grid {
|
||||||
state: State,
|
state: State,
|
||||||
|
|
@ -214,6 +238,8 @@ mod grid {
|
||||||
Populate(Cell),
|
Populate(Cell),
|
||||||
Ticked {
|
Ticked {
|
||||||
result: Result<Life, TickError>,
|
result: Result<Life, TickError>,
|
||||||
|
tick_duration: Duration,
|
||||||
|
tick_amount: usize,
|
||||||
version: usize,
|
version: usize,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
@ -240,16 +266,29 @@ mod grid {
|
||||||
const MIN_SCALING: f32 = 0.1;
|
const MIN_SCALING: f32 = 0.1;
|
||||||
const MAX_SCALING: f32 = 2.0;
|
const MAX_SCALING: f32 = 2.0;
|
||||||
|
|
||||||
|
pub fn cell_count(&self) -> usize {
|
||||||
|
self.state.cell_count()
|
||||||
|
}
|
||||||
|
|
||||||
pub fn tick(
|
pub fn tick(
|
||||||
&mut self,
|
&mut self,
|
||||||
amount: usize,
|
amount: usize,
|
||||||
) -> Option<impl Future<Output = Message>> {
|
) -> Option<impl Future<Output = Message>> {
|
||||||
use iced::futures::FutureExt;
|
|
||||||
|
|
||||||
let version = self.version;
|
let version = self.version;
|
||||||
let tick = self.state.tick(amount)?;
|
let tick = self.state.tick(amount)?;
|
||||||
|
|
||||||
Some(tick.map(move |result| Message::Ticked { result, version }))
|
Some(async move {
|
||||||
|
let start = Instant::now();
|
||||||
|
let result = tick.await;
|
||||||
|
let tick_duration = start.elapsed() / amount as u32;
|
||||||
|
|
||||||
|
Message::Ticked {
|
||||||
|
result,
|
||||||
|
version,
|
||||||
|
tick_duration,
|
||||||
|
tick_amount: amount,
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) {
|
||||||
|
|
@ -259,25 +298,36 @@ mod grid {
|
||||||
self.cache.clear();
|
self.cache.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update(&mut self, message: Message) {
|
pub fn update(
|
||||||
|
&mut self,
|
||||||
|
message: Message,
|
||||||
|
) -> Option<(Duration, usize)> {
|
||||||
match message {
|
match message {
|
||||||
Message::Populate(cell) => {
|
Message::Populate(cell) => {
|
||||||
self.state.populate(cell);
|
self.state.populate(cell);
|
||||||
self.cache.clear()
|
self.cache.clear();
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
Message::Ticked {
|
Message::Ticked {
|
||||||
result: Ok(life),
|
result: Ok(life),
|
||||||
version,
|
version,
|
||||||
|
tick_duration,
|
||||||
|
tick_amount,
|
||||||
} if version == self.version => {
|
} if version == self.version => {
|
||||||
self.state.update(life);
|
self.state.update(life);
|
||||||
self.cache.clear()
|
self.cache.clear();
|
||||||
|
|
||||||
|
Some((tick_duration, tick_amount))
|
||||||
}
|
}
|
||||||
Message::Ticked {
|
Message::Ticked {
|
||||||
result: Err(error), ..
|
result: Err(error), ..
|
||||||
} => {
|
} => {
|
||||||
dbg!(error);
|
dbg!(error);
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
Message::Ticked { .. } => {}
|
Message::Ticked { .. } => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -478,6 +528,10 @@ mod grid {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
|
fn cell_count(&self) -> usize {
|
||||||
|
self.life.len() + self.births.len()
|
||||||
|
}
|
||||||
|
|
||||||
fn contains(&self, cell: &Cell) -> bool {
|
fn contains(&self, cell: &Cell) -> bool {
|
||||||
self.life.contains(cell) || self.births.contains(cell)
|
self.life.contains(cell) || self.births.contains(cell)
|
||||||
}
|
}
|
||||||
|
|
@ -533,6 +587,18 @@ mod grid {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Life {
|
impl Life {
|
||||||
|
fn len(&self) -> usize {
|
||||||
|
self.cells.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn contains(&self, cell: &Cell) -> bool {
|
||||||
|
self.cells.contains(cell)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn populate(&mut self, cell: Cell) {
|
||||||
|
self.cells.insert(cell);
|
||||||
|
}
|
||||||
|
|
||||||
fn tick(&mut self) {
|
fn tick(&mut self) {
|
||||||
let mut adjacent_life = FxHashMap::default();
|
let mut adjacent_life = FxHashMap::default();
|
||||||
|
|
||||||
|
|
@ -559,14 +625,6 @@ mod grid {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains(&self, cell: &Cell) -> bool {
|
|
||||||
self.cells.contains(cell)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn populate(&mut self, cell: Cell) {
|
|
||||||
self.cells.insert(cell);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn iter(&self) -> impl Iterator<Item = &Cell> {
|
pub fn iter(&self) -> impl Iterator<Item = &Cell> {
|
||||||
self.cells.iter()
|
self.cells.iter()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,12 @@ const ACTIVE: Color = Color::from_rgb(
|
||||||
0xDA as f32 / 255.0,
|
0xDA as f32 / 255.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const DESTRUCTIVE: Color = Color::from_rgb(
|
||||||
|
0xC0 as f32 / 255.0,
|
||||||
|
0x47 as f32 / 255.0,
|
||||||
|
0x47 as f32 / 255.0,
|
||||||
|
);
|
||||||
|
|
||||||
const HOVERED: Color = Color::from_rgb(
|
const HOVERED: Color = Color::from_rgb(
|
||||||
0x67 as f32 / 255.0,
|
0x67 as f32 / 255.0,
|
||||||
0x7B as f32 / 255.0,
|
0x7B as f32 / 255.0,
|
||||||
|
|
@ -55,6 +61,38 @@ impl button::StyleSheet for Button {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct Clear;
|
||||||
|
|
||||||
|
impl button::StyleSheet for Clear {
|
||||||
|
fn active(&self) -> button::Style {
|
||||||
|
button::Style {
|
||||||
|
background: Some(Background::Color(DESTRUCTIVE)),
|
||||||
|
border_radius: 3,
|
||||||
|
text_color: Color::WHITE,
|
||||||
|
..button::Style::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hovered(&self) -> button::Style {
|
||||||
|
button::Style {
|
||||||
|
background: Some(Background::Color(Color {
|
||||||
|
a: 0.5,
|
||||||
|
..DESTRUCTIVE
|
||||||
|
})),
|
||||||
|
text_color: Color::WHITE,
|
||||||
|
..self.active()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pressed(&self) -> button::Style {
|
||||||
|
button::Style {
|
||||||
|
border_width: 1,
|
||||||
|
border_color: Color::WHITE,
|
||||||
|
..self.hovered()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct Slider;
|
pub struct Slider;
|
||||||
|
|
||||||
impl slider::StyleSheet for Slider {
|
impl slider::StyleSheet for Slider {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue