Since the last post I added both the Arm
and Belt
Structure
.
Previously there was only the Module
that had no orientation.
For the Belt
and Arm
the orientation/direction matters since both are supposed to move items from A
to B
, hence I added a type for it added:
pub enum Dir {
N,
E,
S,
W,
}
Since I only plan on allowing 90
degree rotations, supporting only the four directions should be good enough.
Since now there’s a need to support multiple Structure
s and orientations, the editor became quite complex.
I tried to find a reasonable character mapping:
impl Structure {
pub fn parse(c: char) -> Option<Self> {
match c {
'^' => Some(Self::Belt(Belt::n())),
'>' => Some(Self::Belt(Belt::e())),
'v' => Some(Self::Belt(Belt::s())),
'<' => Some(Self::Belt(Belt::w())),
'N' => Some(Self::Belt(Belt {
dir: Dir::N,
content: Some(Material::Wood),
})),
')' => Some(Self::Belt(Belt {
dir: Dir::E,
content: Some(Material::Wood),
})),
'U' => Some(Self::Belt(Belt {
dir: Dir::S,
content: Some(Material::Wood),
})),
'(' => Some(Self::Belt(Belt {
dir: Dir::W,
content: Some(Material::Wood),
})),
'a' => Some(Self::Arm(Arm::n())),
'e' => Some(Self::Arm(Arm::e())),
'A' => Some(Self::Arm(Arm::s())),
'E' => Some(Self::Arm(Arm::w())),
'M' => Some(Self::Module(Module::default())),
_ => None,
}
}
}
With an example Blueprint
now looking like this:
let mut bp = Blueprint::parse(
"MMMMMMMMMM\
MMMMMMMMMM\
MMMM MM<<<\
MMMMMMMMM^\
))))>vMMM^\
MMMMMvMMM^\
MMMMMUMMMa\
MMMMM>>)>>\
MMMMMMMMMM\
MMMMMMMMMM",
)
.unwrap();
I also added some Material
s such as Wood
so the Arm
s and Belt
s have something to move around.
There’s now also very basic simulation logic, where the content of Belt
s is being moved around.
Arms simply connect two structures, allowing material flow between them.
impl Blueprint {
...
pub fn step(&mut self) -> bool {
let mut changed = false;
let mut blocked = HashSet::new();
for row in 0..self.structures.len() {
for col in 0..self.structures[row].len() {
let pos = Pos {
row: row as u8,
col: col as u8,
};
if blocked.contains(&pos) {
continue;
}
if let Some(current) = &self.structures[row][col] {
match current {
Structure::Belt(belt) => {
if let Some(pos_target) = Self::neighbour(&pos, belt.dir) {
if let Some(target) = &self.structures[pos_target.row as usize]
[pos_target.col as usize]
{
let (new_current, new_target, new_changed) =
Self::interact(current.clone(), target.clone());
if new_changed {
blocked.insert(pos_target.clone());
}
changed = changed || new_changed;
self.structures[row][col] = Some(new_current);
self.structures[pos_target.row as usize]
[pos_target.col as usize] = Some(new_target);
}
}
}
Structure::Arm(arm) => {
...
}
Structure::Module(_) => (),
}
}
}
}
changed
}
fn interact(mut source: Structure, mut target: Structure) -> (Structure, Structure, bool) {
let mut changed = false;
match (&mut source, &mut target) {
(Structure::Belt(bs), Structure::Belt(bt)) => {
match (&mut bs.content, &mut bt.content) {
(Some(_), None) => {
changed = true;
std::mem::swap(&mut bs.content, &mut bt.content)
}
_ => (),
}
}
_ => (),
}
(source, target, changed)
}
}
Combined with the rendering of a Blueprint
to text, it’s now possible to visualize the behavior of the currently bugged simulation:
loop {
bp.render();
println!("\n\n------------------------------------------\n\n");
let changed = bp.step();
if !changed {
bp.render();
break;
}
}
MMMMMMMMMM
MMMMMMMMMM
MMMM MM<<<
MMMMMMMMM^
))))>vMMM^
MMMMMvMMM^
MMMMMUMMMa
MMMMM>>)>>
MMMMMMMMMM
MMMMMMMMMM
------------------------------------------
MMMMMMMMMM
MMMMMMMMMM
MMMM MM<<<
MMMMMMMMM^
)))>)vMMM^
MMMMMvMMM^
MMMMMvMMMa
MMMMM)>>)>
MMMMMMMMMM
MMMMMMMMMM
------------------------------------------
MMMMMMMMMM
MMMMMMMMMM
MMMM MM<<<
MMMMMMMMM^
))>)>UMMM^
MMMMMvMMM^
MMMMMvMMMa
MMMMM>)>>)
MMMMMMMMMM
MMMMMMMMMM
------------------------------------------
MMMMMMMMMM
MMMMMMMMMM
MMMM MM<<<
MMMMMMMMM^
)>)>)vMMM^
MMMMMUMMMN
MMMMMvMMMa
MMMMM>>)>>
MMMMMMMMMM
MMMMMMMMMM
------------------------------------------
MMMMMMMMMM
MMMMMMMMMM
MMMM MM<<<
MMMMMMMMM^
>)>)>UMMMN
MMMMMvMMM^
MMMMMUMMMa
MMMMM>>>)>
MMMMMMMMMM
MMMMMMMMMM
...