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::hash::*;
6use crate::util::parse::*;
7use crate::util::point::*;
8
9pub fn parse(input: &str) -> Vec<i64> {
10    input.iter_signed().collect()
11}
12
13pub fn part1(input: &[i64]) -> usize {
14    paint(input, 0).len()
15}
16
17pub fn part2(input: &[i64]) -> String {
18    let hull = paint(input, 1);
19
20    // Filter only white panels
21    let panels: Vec<_> = hull.iter().filter(|&(_, &v)| v == 1).map(|(&k, _)| k).collect();
22
23    // Get maximum extents
24    let mut x1 = i32::MAX;
25    let mut x2 = i32::MIN;
26    let mut y1 = i32::MAX;
27    let mut y2 = i32::MIN;
28
29    for &point in &panels {
30        x1 = x1.min(point.x);
31        x2 = x2.max(point.x);
32        y1 = y1.min(point.y);
33        y2 = y2.max(point.y);
34    }
35
36    // Convert panels to characters
37    let width = (x2 - x1 + 1) as usize;
38    let height = (y2 - y1 + 1) as usize;
39    let offset = Point::new(x1, y1);
40    let mut image = vec!['.'; width * height];
41
42    for &point in &panels {
43        let adjusted = point - offset;
44        let index = (width * adjusted.y as usize) + (adjusted.x as usize);
45        image[index] = '#';
46    }
47
48    // Convert to multiline string
49    let mut result = image
50        .chunks_exact(width)
51        .map(|row| row.iter().collect())
52        .collect::<Vec<String>>()
53        .join("\n");
54    result.insert(0, '\n');
55    result
56}
57
58fn paint(input: &[i64], initial: i64) -> FastMap<Point, i64> {
59    let mut computer = Computer::new(input);
60    let mut position = ORIGIN;
61    let mut direction = UP;
62    let mut hull = FastMap::with_capacity(5_000);
63
64    hull.insert(position, initial);
65
66    loop {
67        let panel = hull.get(&position).unwrap_or(&0);
68        computer.input(*panel);
69
70        match computer.run() {
71            State::Output(color) => {
72                hull.insert(position, color);
73            }
74            _ => break,
75        }
76
77        match computer.run() {
78            State::Output(next) => {
79                direction =
80                    if next == 0 { direction.counter_clockwise() } else { direction.clockwise() };
81                position += direction;
82            }
83            _ => break,
84        }
85    }
86
87    hull
88}