World::init

main
Shad Amethyst 2 years ago
parent 6cee084486
commit 63245aeb69
Signed by: amethyst
GPG Key ID: D970C8DD1D6DEE36

@ -273,6 +273,8 @@ fn main() {
fn run(world: &mut World, steps: usize) -> std::io::Result<()> { fn run(world: &mut World, steps: usize) -> std::io::Result<()> {
let mut stdout = std::io::stdout(); let mut stdout = std::io::stdout();
let mut first = true; let mut first = true;
world.init();
for _ in 0..steps { for _ in 0..steps {
if !first { if !first {
world.step(); world.step();

@ -479,3 +479,29 @@ impl UpdateCommit {
} }
} }
} }
#[derive(Clone)]
#[non_exhaustive]
pub struct InitContext<'a> {
pub world: &'a World,
pub pane: &'a Pane,
pub world_coordinates: (i32, i32),
pub pane_coordinates: (String, usize, usize),
}
impl<'a> InitContext<'a> {
pub fn new(world: &'a World, coordinates: (String, usize, usize)) -> Option<Self> {
let pane = world.get_pane(&coordinates.0)?;
let position = pane.position();
Some(InitContext {
world,
pane,
world_coordinates: (
position.0 + coordinates.1 as i32,
position.1 + coordinates.2 as i32,
),
pane_coordinates: coordinates,
})
}
}

@ -10,6 +10,7 @@ pub struct Pane {
position: (i32, i32), position: (i32, i32),
#[serde(skip)]
pub(crate) signals: Vec<(usize, usize)>, pub(crate) signals: Vec<(usize, usize)>,
} }
@ -56,6 +57,34 @@ impl Pane {
}) })
} }
pub(crate) fn init(&self, name: &str, world: &World) {
for index in 0..self.tiles.len() {
let mut tile = self
.tiles
.borrow_mut(index)
.unwrap_or_else(|| unreachable!());
let ctx = InitContext::new(
world,
(name.to_string(), index % self.width, index / self.width),
)
.unwrap();
tile.init(ctx);
}
}
pub(crate) fn init_signals(&mut self) {
let mut signals = Vec::new();
for (x, y, tile) in self.tiles_iter() {
if tile.signal().is_some() {
signals.push((x, y));
}
}
self.signals = signals;
}
/// Returns the width of the current pane /// Returns the width of the current pane
/// ///
/// ## Example /// ## Example
@ -480,9 +509,13 @@ impl Pane {
commit.apply(self) commit.apply(self)
} }
pub fn tiles(&self) -> &VecCell<FullTile> {
&self.tiles
}
/// Returns an iterator over the tiles and their coordinates /// Returns an iterator over the tiles and their coordinates
#[inline] #[inline]
pub fn tiles(&self) -> impl Iterator<Item = (usize, usize, VecRef<'_, FullTile>)> + '_ { pub fn tiles_iter(&self) -> impl Iterator<Item = (usize, usize, VecRef<'_, FullTile>)> + '_ {
self.tiles self.tiles
.iter() .iter()
.enumerate() .enumerate()
@ -492,7 +525,7 @@ impl Pane {
/// Draws the Pane at `(dx + self.position.0, dy + self.position.1)` on a [`TextSurface`]. /// Draws the Pane at `(dx + self.position.0, dy + self.position.1)` on a [`TextSurface`].
/// Empty tiles will leave the `TextSurface` untouched, but tiles are free to modify the characters around them. /// Empty tiles will leave the `TextSurface` untouched, but tiles are free to modify the characters around them.
pub fn draw(&self, dx: i32, dy: i32, surface: &mut TextSurface) { pub fn draw(&self, dx: i32, dy: i32, surface: &mut TextSurface) {
for (x, y, tile) in self.tiles() { for (x, y, tile) in self.tiles_iter() {
let x = x as i32 + dx + self.position.0 as i32; let x = x as i32 + dx + self.position.0 as i32;
let y = y as i32 + dy + self.position.1 as i32; let y = y as i32 + dy + self.position.1 as i32;
@ -614,4 +647,41 @@ mod test {
} }
} }
} }
#[test]
fn test_init() {
use crate::tile::Wire;
use std::collections::HashSet;
use Orientation::*;
let mut pane = test_tile_setup!(
2,
2,
[
Wire::new(Horizontal),
Wire::new(Vertical),
Wire::new(Any),
()
]
);
assert_eq!(pane.signals, vec![]);
pane.get_mut((0, 0))
.unwrap()
.set_signal(Some(Signal::empty((0, 0), Direction::Right)));
pane.get_mut((1, 0))
.unwrap()
.set_signal(Some(Signal::empty((1, 0), Direction::Right)));
pane.init_signals();
assert_eq!(
pane.signals
.iter()
.copied()
.collect::<HashSet<(usize, usize)>>(),
HashSet::from_iter(vec![(0, 0), (1, 0)].into_iter())
);
}
} }

@ -29,6 +29,12 @@ impl FullTile {
} }
} }
pub fn init<'b>(&'b mut self, context: InitContext<'b>) {
if let Some(ref mut tile) = self.cell {
tile.init(context)
}
}
pub fn accepts_signal(&self, direction: Direction) -> bool { pub fn accepts_signal(&self, direction: Direction) -> bool {
match self.cell { match self.cell {
Some(ref tile) => self.state.accepts_signal() && tile.accepts_signal(direction), Some(ref tile) => self.state.accepts_signal() && tile.accepts_signal(direction),

@ -141,7 +141,15 @@ include!(concat!(env!("OUT_DIR"), "/anytile.rs"));
/// ``` /// ```
#[enum_dispatch(AnyTile)] #[enum_dispatch(AnyTile)]
pub trait Tile: std::clone::Clone + std::fmt::Debug + Serialize + for<'d> Deserialize<'d> { pub trait Tile: std::clone::Clone + std::fmt::Debug + Serialize + for<'d> Deserialize<'d> {
#[inline]
#[allow(unused_variables)]
fn init<'b>(&'b mut self, context: InitContext<'b>) {
// noop
}
/// Function to be called when the tile needs to be updated. /// Function to be called when the tile needs to be updated.
///
/// This function might be called every frame, so as much work should be done in [`Tile::init()`] instead.
#[inline] #[inline]
fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) { fn update<'b>(&'b mut self, mut context: UpdateContext<'b>) {
context.next_state(); context.next_state();

@ -1,7 +1,7 @@
use super::*; use super::*;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::collections::HashMap; use std::collections::HashMap;
use veccell::{VecRef, VecRefMut}; use veccell::VecRef;
#[derive(Debug, Serialize, Deserialize)] #[derive(Debug, Serialize, Deserialize)]
pub struct World { pub struct World {
@ -15,6 +15,19 @@ impl World {
} }
} }
/// Method to be called before running the simulation
// TODO: set a flag to true?
pub fn init(&mut self) {
for (name, pane) in self.panes.iter() {
pane.init(name, self);
}
for pane in self.panes.values_mut() {
pane.init_signals();
}
}
/// Runs a single step of the simulation
pub fn step(&mut self) { pub fn step(&mut self) {
let mut outbound_signals = Vec::new(); let mut outbound_signals = Vec::new();

@ -172,7 +172,7 @@ mod test {
assert_no_signal!(pane, (1, 0)); assert_no_signal!(pane, (1, 0));
pane.step(); pane.step();
for (_, _, tile) in pane.tiles() { for tile in pane.tiles() {
assert!(tile.signal().is_none()); assert!(tile.signal().is_none());
} }

Loading…
Cancel
Save