aoc/year2019/
day11.rs

1//! # Space Police
2//!
3//! This problem is a variant of [Langton's Ant](https://en.wikipedia.org/wiki/Langton%27s_ant).
4use super::intcode::*;
5use crate::util::grid::*;
6use crate::util::hash::*;
7use crate::util::parse::*;
8use crate::util::point::*;
9
10pub fn parse(input: &str) -> Vec<i64> {
11    input.iter_signed().collect()
12}
13
14pub fn part1(input: &[i64]) -> usize {
15    paint(input, 0).len()
16}
17
18pub fn part2(input: &[i64]) -> String {
19    let hull = paint(input, 1);
20
21    // Filter only white panels
22    let panels: Vec<_> = hull.iter().filter(|&(_, &v)| v == 1).map(|(&k, _)| k).collect();
23
24    // Get maximum extents
25    let (x1, x2, y1, y2) = panels.iter().fold(
26        (i32::MAX, i32::MIN, i32::MAX, i32::MIN),
27        |(min_x, max_x, min_y, max_y), p| {
28            (min_x.min(p.x), max_x.max(p.x), min_y.min(p.y), max_y.max(p.y))
29        },
30    );
31
32    // Convert panels to characters
33    let width = x2 - x1 + 2; // Leave room for newline character.
34    let height = y2 - y1 + 1;
35    let mut image = Grid::new(width, height, b'.');
36
37    let offset = Point::new(x1 - 1, y1);
38    panels.iter().for_each(|&point| image[point - offset] = b'#');
39
40    (0..height).for_each(|y| image[Point::new(0, y)] = b'\n');
41
42    String::from_utf8(image.bytes).unwrap()
43}
44
45fn paint(input: &[i64], initial: i64) -> FastMap<Point, i64> {
46    let mut computer = Computer::new(input);
47    let mut position = ORIGIN;
48    let mut direction = UP;
49    let mut hull = FastMap::with_capacity(5_000);
50
51    hull.insert(position, initial);
52
53    loop {
54        let panel = hull.entry(position).or_default();
55        computer.input(*panel);
56
57        match computer.run() {
58            State::Output(color) => {
59                *panel = color;
60            }
61            _ => break,
62        }
63
64        match computer.run() {
65            State::Output(next) => {
66                direction =
67                    if next == 0 { direction.counter_clockwise() } else { direction.clockwise() };
68                position += direction;
69            }
70            _ => break,
71        }
72    }
73
74    hull
75}