day15 fast
This commit is contained in:
parent
244e308200
commit
f2ad6c7ad8
3 changed files with 209 additions and 0 deletions
204
src/day15/main.rs
Normal file
204
src/day15/main.rs
Normal file
|
@ -0,0 +1,204 @@
|
|||
use std::collections::HashMap;
|
||||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
|
||||
use aoc2019::intcode;
|
||||
|
||||
fn main() -> Result<(), Box<dyn Error>> {
|
||||
let f = File::open("input15")?;
|
||||
let computer = intcode::Computer::from(f);
|
||||
let mut map = Map::new();
|
||||
let steps = map.walk(&XY { x: 0, y: 0 }, &computer, 0).unwrap();
|
||||
|
||||
for y in map.ymin..=map.ymax {
|
||||
for x in map.xmin..=map.xmax {
|
||||
if x == 0 && y == 0 {
|
||||
print!("0");
|
||||
continue;
|
||||
}
|
||||
let status = map.m.get(&XY { x, y }).unwrap_or(&Status::Empty);
|
||||
let c = match status {
|
||||
Status::HitWall => "#",
|
||||
Status::MoveComplete => ".",
|
||||
Status::Finished => "X",
|
||||
Status::Empty => " ",
|
||||
Status::Oxigenated => "o",
|
||||
};
|
||||
print!("{}", c);
|
||||
}
|
||||
println!("");
|
||||
}
|
||||
|
||||
println!("i walked {} steps", steps);
|
||||
let steps = map.fill();
|
||||
println!("filled with oxygen after {} minutes", steps);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
struct Map {
|
||||
m: HashMap<XY, Status>,
|
||||
xmin: isize,
|
||||
xmax: isize,
|
||||
ymin: isize,
|
||||
ymax: isize,
|
||||
}
|
||||
|
||||
impl Map {
|
||||
fn new() -> Self {
|
||||
Map::default()
|
||||
}
|
||||
|
||||
fn walk(&mut self, start: &XY, computer: &intcode::Computer, steps: usize) -> Option<usize> {
|
||||
let steps = steps + 1;
|
||||
for dir in 1..=4 {
|
||||
let direction = Direction::from(dir);
|
||||
let xy = start.add((&direction).into());
|
||||
if self.m.contains_key(&xy) {
|
||||
continue;
|
||||
}
|
||||
self.update_limits(&xy);
|
||||
let mut computer = computer.clone();
|
||||
if let Some(status) = computer.run_io(dir) {
|
||||
let status = Status::from(status);
|
||||
self.m.insert(xy.clone(), status.clone());
|
||||
match status {
|
||||
Status::HitWall => (),
|
||||
Status::MoveComplete => match self.walk(&xy, &computer, steps) {
|
||||
Some(i) => return Some(i + 1),
|
||||
None => (),
|
||||
},
|
||||
Status::Finished => return Some(1),
|
||||
_ => unreachable!("unknown status"),
|
||||
}
|
||||
} else {
|
||||
unreachable!("computer unexpectedly halted");
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn fill(&mut self) -> usize {
|
||||
let mut src: Vec<XY> = self
|
||||
.m
|
||||
.iter()
|
||||
.filter_map(|(xy, status)| match status {
|
||||
Status::Finished => Some(xy),
|
||||
_ => None,
|
||||
})
|
||||
.cloned()
|
||||
.collect();
|
||||
let mut steps = 0;
|
||||
while src.len() > 0 {
|
||||
steps += 1;
|
||||
src.iter()
|
||||
.for_each(|xy| *self.m.get_mut(xy).unwrap() = Status::Oxigenated);
|
||||
src = src
|
||||
.into_iter()
|
||||
.map(|xy| {
|
||||
(1..=4)
|
||||
.map(Direction::from)
|
||||
.map(move |d| xy.add((&d).into()))
|
||||
})
|
||||
.flatten()
|
||||
.filter(|xy| match self.m.get(xy) {
|
||||
Some(Status::MoveComplete) => true,
|
||||
_ => false,
|
||||
})
|
||||
.collect();
|
||||
}
|
||||
assert_eq!(
|
||||
self.m
|
||||
.values()
|
||||
.filter(|status| match status {
|
||||
Status::MoveComplete => true,
|
||||
_ => false,
|
||||
})
|
||||
.count(),
|
||||
0
|
||||
);
|
||||
steps - 1
|
||||
}
|
||||
|
||||
fn update_limits(&mut self, xy: &XY) {
|
||||
if self.xmin > xy.x {
|
||||
self.xmin = xy.x
|
||||
}
|
||||
if self.xmax < xy.x {
|
||||
self.xmax = xy.x
|
||||
}
|
||||
if self.ymin > xy.y {
|
||||
self.ymin = xy.y
|
||||
}
|
||||
if self.ymax < xy.y {
|
||||
self.ymax = xy.y
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum Direction {
|
||||
North = 1,
|
||||
South = 2,
|
||||
West = 3,
|
||||
East = 4,
|
||||
}
|
||||
|
||||
impl From<isize> for Direction {
|
||||
fn from(i: isize) -> Self {
|
||||
match i {
|
||||
1 => Direction::North,
|
||||
2 => Direction::South,
|
||||
3 => Direction::West,
|
||||
4 => Direction::East,
|
||||
_ => unreachable!("no status for computer output"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<(isize, isize)> for &Direction {
|
||||
fn into(self) -> (isize, isize) {
|
||||
match self {
|
||||
Direction::North => (0, 1),
|
||||
Direction::South => (0, -1),
|
||||
Direction::West => (-1, 0),
|
||||
Direction::East => (1, 0),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
enum Status {
|
||||
HitWall = 0,
|
||||
MoveComplete = 1,
|
||||
Finished = 2,
|
||||
Empty = 3,
|
||||
Oxigenated = 4,
|
||||
}
|
||||
|
||||
impl From<isize> for Status {
|
||||
fn from(i: isize) -> Self {
|
||||
match i {
|
||||
0 => Status::HitWall,
|
||||
1 => Status::MoveComplete,
|
||||
2 => Status::Finished,
|
||||
_ => unreachable!("no status for computer output"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
|
||||
struct XY {
|
||||
x: isize,
|
||||
y: isize,
|
||||
}
|
||||
|
||||
impl XY {
|
||||
fn add(&self, delta: (isize, isize)) -> XY {
|
||||
XY {
|
||||
x: self.x + delta.0,
|
||||
y: self.y + delta.1,
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue