Simplify logic and limit ticks in game_of_life

This commit is contained in:
Héctor Ramón Jiménez 2020-05-02 10:48:42 +02:00
parent 0025b8c3f8
commit cc8f5b6fc8

View file

@ -19,26 +19,16 @@ pub fn main() {
#[derive(Default)] #[derive(Default)]
struct GameOfLife { struct GameOfLife {
grid: Grid, grid: Grid,
state: State, is_playing: bool,
speed: u64, speed: usize,
next_speed: Option<u64>, next_speed: Option<usize>,
toggle_button: button::State, toggle_button: button::State,
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_duration: Duration,
tick_amount: usize, queued_ticks: usize,
} last_ticks: usize,
enum State {
Paused,
Playing { last_tick: Instant },
}
impl Default for State {
fn default() -> State {
State::Paused
}
} }
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
@ -73,68 +63,48 @@ 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) => {
if let Some((tick_duration, tick_amount)) = if let Some(tick_duration) = self.grid.update(message) {
self.grid.update(message)
{
self.tick_duration = tick_duration; self.tick_duration = tick_duration;
self.tick_amount = tick_amount;
} }
} }
Message::Tick(_) | Message::Next => match &mut self.state { Message::Tick(_) | Message::Next => {
State::Paused => { if let Some(task) = self.grid.tick(self.queued_ticks + 1) {
if let Some(task) = self.grid.tick(1) { self.last_ticks = self.queued_ticks;
return Command::perform(task, Message::Grid); self.queued_ticks = 0;
if let Some(speed) = self.next_speed.take() {
self.speed = speed;
} }
return Command::perform(task, Message::Grid);
} else {
self.queued_ticks = (self.queued_ticks + 1).min(self.speed);
} }
State::Playing { last_tick } => { }
let seconds_elapsed =
last_tick.elapsed().as_millis() as f32 / 1000.0;
let needed_ticks =
(self.speed as f32 * seconds_elapsed).ceil() as usize;
if let Some(task) = self.grid.tick(needed_ticks.max(1)) {
*last_tick = Instant::now();
if let Some(speed) = self.next_speed.take() {
self.speed = speed;
}
return Command::perform(task, Message::Grid);
}
}
},
Message::Toggle => { Message::Toggle => {
self.state = match self.state { self.is_playing = !self.is_playing;
State::Paused => State::Playing {
last_tick: Instant::now(),
},
State::Playing { .. } => State::Paused,
};
} }
Message::Clear => { Message::Clear => {
self.grid.clear(); self.grid.clear();
} }
Message::SpeedChanged(speed) => match self.state { Message::SpeedChanged(speed) => {
State::Paused => { if self.is_playing {
self.speed = speed.round() as u64; self.next_speed = Some(speed.round() as usize);
} else {
self.speed = speed.round() as usize;
} }
State::Playing { .. } => { }
self.next_speed = Some(speed.round() as u64);
}
},
} }
Command::none() Command::none()
} }
fn subscription(&self) -> Subscription<Message> { fn subscription(&self) -> Subscription<Message> {
match self.state { if self.is_playing {
State::Paused => Subscription::none(), time::every(Duration::from_millis(1000 / self.speed as u64))
State::Playing { .. } => { .map(Message::Tick)
time::every(Duration::from_millis(1000 / self.speed)) } else {
.map(Message::Tick) Subscription::none()
}
} }
} }
@ -144,11 +114,7 @@ impl Application for GameOfLife {
.push( .push(
Button::new( Button::new(
&mut self.toggle_button, &mut self.toggle_button,
Text::new(if let State::Paused = self.state { Text::new(if self.is_playing { "Pause" } else { "Play" }),
"Play"
} else {
"Pause"
}),
) )
.on_press(Message::Toggle) .on_press(Message::Toggle)
.style(style::Button), .style(style::Button),
@ -185,7 +151,7 @@ impl Application for GameOfLife {
.push( .push(
Text::new(format!( Text::new(format!(
"{:?} ({})", "{:?} ({})",
self.tick_duration, self.tick_amount self.tick_duration, self.last_ticks
)) ))
.size(14), .size(14),
); );
@ -239,7 +205,6 @@ mod grid {
Ticked { Ticked {
result: Result<Life, TickError>, result: Result<Life, TickError>,
tick_duration: Duration, tick_duration: Duration,
tick_amount: usize,
version: usize, version: usize,
}, },
} }
@ -286,7 +251,6 @@ mod grid {
result, result,
version, version,
tick_duration, tick_duration,
tick_amount: amount,
} }
}) })
} }
@ -298,10 +262,7 @@ mod grid {
self.cache.clear(); self.cache.clear();
} }
pub fn update( pub fn update(&mut self, message: Message) -> Option<Duration> {
&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);
@ -313,12 +274,11 @@ mod grid {
result: Ok(life), result: Ok(life),
version, version,
tick_duration, 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)) Some(tick_duration)
} }
Message::Ticked { Message::Ticked {
result: Err(error), .. result: Err(error), ..