diff --git a/life/src/main.rs b/life/src/main.rs index c304b25..02d3617 100644 --- a/life/src/main.rs +++ b/life/src/main.rs @@ -1,15 +1,14 @@ // TODO: // * Volume slider -// * Invert mute/unmute icons // * Only move camera when cells move out of view +// * "Follow" enhancement: Zoom in/out +// * optimize simulation_step // * Stop creating cells when I didn't mean to (clicking UI, click + dragging) // * Keep some controls open when main ui panel is closed -// * Exclude power button from web build // * Show shadow of piece (same tile, just with alpha transparency) // * Dark mode // * Make click and drag feel better // * Add arrow keys to move around -// * "Follow" enhancement: Zoom in/out #![allow(clippy::complexity)] // Only because of FromTemplat macros unfortunately... #![allow(dead_code)] @@ -821,61 +820,45 @@ enum SimulationPlayback { fn simulation_step( q: Query<(Entity, &Coordinates), With>, mut writer: MessageWriter, + mut alive: Local>, + mut candidates: Local>, ) { - fn is_cell_alive( - coordinates: &Coordinates, - query: &Query<(Entity, &Coordinates), With>, - ) -> bool { - query.iter().any(|(_e, c)| *c == *coordinates) - } - - fn living_neighbors( - c: &Coordinates, - query: &Query<(Entity, &Coordinates), With>, - ) -> usize { + let living_neighbors = |a: &HashMap, c: &Coordinates| -> usize { c.neighbors() .filter(|neighbor| { - query - .iter() - .any(|(_e, coordinates)| *neighbor == *coordinates) + a.contains_key(neighbor) }) .count() - } + }; - fn cell_entity( - coordinates: &Coordinates, - query: Query<(Entity, &Coordinates), With>, - ) -> Option { - query - .iter() - .find_map(|(e, c)| (*c == *coordinates).then_some(e)) - } + // Reset alive cell cache + *alive = q.iter().map(|(e, c)| (c.clone(), e)).collect(); - // Collect list of candidate positions... - let mut coordinates: HashSet = HashSet::new(); + // Clear candidate coordinates + candidates.clear(); // Put all dead cells neighboring living cells into the coordinates hashset // Each living cell q.iter().for_each(|(_e, c)| { - coordinates.insert(c.clone()); + candidates.insert(c.clone()); // Iterator over neighbor positions // Filter to just dead neighbors c.neighbors() - .filter(|c| !is_cell_alive(c, &q)) + .filter(|c| !alive.contains_key(c)) .for_each(|c| { - coordinates.insert(c); + candidates.insert(c); }); }); // Get Neighbor Count of living cells - coordinates.iter().for_each(|c| { - let num_living_neighbors = living_neighbors(c, &q); - let is_living = is_cell_alive(c, &q); + candidates.iter().for_each(|c| { + let num_living_neighbors = living_neighbors(&*alive, c); + let is_living = alive.contains_key(c); match num_living_neighbors { ..2 | 4.. => { if is_living { - writer.write(Lifecycle::Dead(cell_entity(c, q).unwrap())); + writer.write(Lifecycle::Dead(alive.get(c).cloned().unwrap())); } } 2 => debug!("continue"),