remove a vec allocation from simulation step
This commit is contained in:
parent
e0d0a297b9
commit
e6d8c1246f
1 changed files with 92 additions and 90 deletions
|
@ -16,6 +16,7 @@ pub struct Machine {
|
||||||
board: Board,
|
board: Board,
|
||||||
marbles: Vec<Pos>,
|
marbles: Vec<Pos>,
|
||||||
powered: Vec<Pos>,
|
powered: Vec<Pos>,
|
||||||
|
events: Vec<Event>,
|
||||||
|
|
||||||
input: Vec<u8>,
|
input: Vec<u8>,
|
||||||
input_index: usize,
|
input_index: usize,
|
||||||
|
@ -23,12 +24,27 @@ pub struct Machine {
|
||||||
steps: usize,
|
steps: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
enum Event {
|
||||||
|
Stay,
|
||||||
|
/// (new_pos, new_dir)
|
||||||
|
MoveTo(Pos, Direction),
|
||||||
|
/// (new_pos, new_dir, trigger_pos)
|
||||||
|
Trigger(Pos, Direction, Pos),
|
||||||
|
/// (other, new_dir)
|
||||||
|
/// other marble should be set to reverse of new_dir
|
||||||
|
/// and should be cancelled if it had a movement event planned
|
||||||
|
Bounce(usize, Direction),
|
||||||
|
Remove,
|
||||||
|
}
|
||||||
|
|
||||||
impl Machine {
|
impl Machine {
|
||||||
pub fn new_empty(input: Vec<u8>, width: usize) -> Self {
|
pub fn new_empty(input: Vec<u8>, width: usize) -> Self {
|
||||||
Self {
|
Self {
|
||||||
board: Board::new_empty(width, width),
|
board: Board::new_empty(width, width),
|
||||||
marbles: Vec::new(),
|
marbles: Vec::new(),
|
||||||
powered: Vec::new(),
|
powered: Vec::new(),
|
||||||
|
events: Vec::new(),
|
||||||
input,
|
input,
|
||||||
input_index: 0,
|
input_index: 0,
|
||||||
output: Vec::new(),
|
output: Vec::new(),
|
||||||
|
@ -113,39 +129,26 @@ impl Machine {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
self.events.clear();
|
||||||
enum Event {
|
for &pos in &self.marbles {
|
||||||
Stay,
|
|
||||||
/// (new_pos, new_dir)
|
|
||||||
MoveTo(Pos, Direction),
|
|
||||||
/// (new_pos, new_dir, trigger_pos)
|
|
||||||
Trigger(Pos, Direction, Pos),
|
|
||||||
/// (other, new_dir)
|
|
||||||
/// other marble should be set to reverse of new_dir
|
|
||||||
/// and should be cancelled if it had a movement event planned
|
|
||||||
Bounce(usize, Direction),
|
|
||||||
Remove,
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut marble_events: Vec<Event> = self
|
|
||||||
.marbles
|
|
||||||
.iter()
|
|
||||||
.map(|&pos| {
|
|
||||||
let marble = self.board.get(pos).unwrap();
|
let marble = self.board.get(pos).unwrap();
|
||||||
let Tile::Marble { value, dir } = marble else {
|
let Tile::Marble { value, dir } = marble else {
|
||||||
panic!("broken marble");
|
panic!("broken marble");
|
||||||
};
|
};
|
||||||
let front_pos = dir.step(pos);
|
let front_pos = dir.step(pos);
|
||||||
let Some(front_tile) = self.board.get(front_pos) else {
|
let Some(front_tile) = self.board.get(front_pos) else {
|
||||||
return Event::Stay;
|
self.events.push(Event::Stay);
|
||||||
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Tile::Powerable(PTile::Bag, _) = front_tile {
|
if let Tile::Powerable(PTile::Bag, _) = front_tile {
|
||||||
return Event::Remove;
|
self.events.push(Event::Remove);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
if let Tile::Powerable(PTile::IO, _) = front_tile {
|
if let Tile::Powerable(PTile::IO, _) = front_tile {
|
||||||
self.output.push(value as u8);
|
self.output.push(value as u8);
|
||||||
return Event::Remove;
|
self.events.push(Event::Remove);
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
let can_move_to = |tile| matches!(tile, Some(Tile::Blank | Tile::Digit(_)));
|
let can_move_to = |tile| matches!(tile, Some(Tile::Blank | Tile::Digit(_)));
|
||||||
|
@ -172,8 +175,7 @@ impl Machine {
|
||||||
}
|
}
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
|
let e = if can_move_to(Some(front_tile)) {
|
||||||
if can_move_to(Some(front_tile)) {
|
|
||||||
Event::MoveTo(front_pos, dir)
|
Event::MoveTo(front_pos, dir)
|
||||||
} else if let Tile::Powerable(PTile::Trigger, _) = front_tile {
|
} else if let Tile::Powerable(PTile::Trigger, _) = front_tile {
|
||||||
let target_pos = dir.step(front_pos);
|
let target_pos = dir.step(front_pos);
|
||||||
|
@ -200,29 +202,29 @@ impl Machine {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Event::Stay
|
Event::Stay
|
||||||
|
};
|
||||||
|
self.events.push(e);
|
||||||
}
|
}
|
||||||
})
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
// resolve bounces
|
// resolve bounces
|
||||||
for i in 0..marble_events.len() {
|
for i in 0..self.events.len() {
|
||||||
let event = marble_events[i];
|
let event = self.events[i];
|
||||||
if let Event::Bounce(other_index, dir) = event {
|
if let Event::Bounce(other_index, dir) = event {
|
||||||
match marble_events[other_index] {
|
match self.events[other_index] {
|
||||||
// cancel bounces on marble that are about to disappear
|
// cancel bounces on marble that are about to disappear
|
||||||
Event::Remove => {
|
Event::Remove => {
|
||||||
marble_events[i] = Event::MoveTo(self.marbles[other_index], dir.opposite())
|
self.events[i] = Event::MoveTo(self.marbles[other_index], dir.opposite())
|
||||||
}
|
}
|
||||||
// let already bouncing marbles continue
|
// let already bouncing marbles continue
|
||||||
Event::Bounce(_, _) => (),
|
Event::Bounce(_, _) => (),
|
||||||
// interrupt any other movement/staying to bounce
|
// interrupt any other movement/staying to bounce
|
||||||
_ => marble_events[other_index] = Event::Bounce(i, dir.opposite()),
|
_ => self.events[other_index] = Event::Bounce(i, dir.opposite()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve deletions of tiles
|
// resolve deletions of tiles
|
||||||
for (i, event) in marble_events.iter().enumerate() {
|
for (i, event) in self.events.iter().enumerate() {
|
||||||
if let Event::Remove = event {
|
if let Event::Remove = event {
|
||||||
self.board.set(self.marbles[i], Tile::Blank);
|
self.board.set(self.marbles[i], Tile::Blank);
|
||||||
}
|
}
|
||||||
|
@ -230,7 +232,7 @@ impl Machine {
|
||||||
|
|
||||||
// resolve triggers
|
// resolve triggers
|
||||||
let mut triggers_activated = Vec::new();
|
let mut triggers_activated = Vec::new();
|
||||||
for event in &mut marble_events {
|
for event in &mut self.events {
|
||||||
if let Event::Trigger(new_pos, dir, trigger_pos) = event {
|
if let Event::Trigger(new_pos, dir, trigger_pos) = event {
|
||||||
triggers_activated.push(*trigger_pos);
|
triggers_activated.push(*trigger_pos);
|
||||||
*event = Event::MoveTo(*new_pos, *dir);
|
*event = Event::MoveTo(*new_pos, *dir);
|
||||||
|
@ -238,10 +240,10 @@ impl Machine {
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve collisions (multiple marbles entering the same space)
|
// resolve collisions (multiple marbles entering the same space)
|
||||||
for i in 0..(marble_events.len() - 1) {
|
for i in 0..(self.events.len() - 1) {
|
||||||
let event = marble_events[i];
|
let event = self.events[i];
|
||||||
if let Event::MoveTo(new_pos, _dir) = event {
|
if let Event::MoveTo(new_pos, _dir) = event {
|
||||||
for other_event in &mut marble_events[(i + 1)..] {
|
for other_event in &mut self.events[(i + 1)..] {
|
||||||
if let Event::MoveTo(other_pos, _other_dir) = other_event {
|
if let Event::MoveTo(other_pos, _other_dir) = other_event {
|
||||||
// todo: maybe sort by direction so the sucessful direction is consistent
|
// todo: maybe sort by direction so the sucessful direction is consistent
|
||||||
if other_pos == &new_pos {
|
if other_pos == &new_pos {
|
||||||
|
@ -253,7 +255,7 @@ impl Machine {
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve movement
|
// resolve movement
|
||||||
for (i, &event) in marble_events.iter().enumerate() {
|
for (i, &event) in self.events.iter().enumerate() {
|
||||||
if let Event::Remove = event {
|
if let Event::Remove = event {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -281,7 +283,7 @@ impl Machine {
|
||||||
}
|
}
|
||||||
|
|
||||||
// resolve deletions of marbles
|
// resolve deletions of marbles
|
||||||
for (i, event) in marble_events.iter().enumerate().rev() {
|
for (i, event) in self.events.iter().enumerate().rev() {
|
||||||
if let Event::Remove = event {
|
if let Event::Remove = event {
|
||||||
self.marbles.remove(i);
|
self.marbles.remove(i);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue