-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday11.rs
145 lines (119 loc) · 3.52 KB
/
day11.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
//! [Day 11: Space Police](https://adventofcode.com/2019/day/11)
use aoc::{ocr, Coord, Grid};
use intcode::{Computer, State};
use rustc_hash::FxHashMap;
#[derive(PartialEq)]
enum Color {
Black,
White,
}
impl From<&Color> for i64 {
fn from(value: &Color) -> Self {
match value {
Color::Black => 0,
Color::White => 1,
}
}
}
struct Robot {
brain: Computer,
panel: FxHashMap<Coord, Color>,
}
impl Robot {
const TURN_LEFT: i64 = 0;
const TURN_RIGHT: i64 = 1;
const MOVES: &[Coord] = &[Coord::UP, Coord::RIGHT, Coord::DOWN, Coord::LEFT];
fn new(brain: &Computer) -> Self {
Self {
brain: brain.clone(),
panel: FxHashMap::default(),
}
}
fn paint(&mut self, initial_color: Color) {
self.brain.reset();
let mut pos = Coord::ZERO;
let mut direction = 0;
self.panel.insert(pos, initial_color);
loop {
// by default (coords are missing), panel is black
let color = self.panel.get(&pos).unwrap_or(&Color::Black);
// provide the current panel color to the computer
self.brain.push(i64::from(color));
// first output is the color to paint the panel
let paint = match self.brain.run() {
State::Output(value) => {
if value == 0 {
Color::Black
} else {
Color::White
}
}
State::Halted => break,
State::Input => panic!(),
};
// second output is the direction the robot should turn
let State::Output(turn) = self.brain.run() else {
panic!()
};
// paint the panel
self.panel.insert(pos, paint);
// update the robot direction
direction = match turn {
Self::TURN_RIGHT => (direction + 1) % 4,
Self::TURN_LEFT => (direction + 3) % 4,
_ => panic!(),
};
// move the robot
pos += Self::MOVES[direction];
}
}
fn to_grid(&self) -> Grid<char> {
let mut ll = Coord::new(i32::MAX, i32::MAX);
let mut ur = Coord::new(i32::MIN, i32::MIN);
for pos in self.panel.keys() {
ll.x = ll.x.min(pos.x);
ll.y = ll.y.min(pos.y);
ur.x = ur.x.max(pos.x);
ur.y = ur.y.max(pos.y);
}
let mut grid = Grid::<char>::with_size(ur.x - ll.x + 1, ur.y - ll.y + 1, '.', ' ');
for (&pos, c) in &self.panel {
if c == &Color::White {
grid[pos + ll] = '#';
}
}
grid
}
fn drawing(&self) -> String {
ocr::scan_5x6(&self.to_grid().to_string())
}
}
struct Puzzle {
brain: Computer,
}
impl Puzzle {
/// Initialize from the puzzle input.
fn new(data: &str) -> Self {
Self {
brain: Computer::load(data),
}
}
/// Solve part one.
fn part1(&self) -> usize {
let mut robot = Robot::new(&self.brain);
robot.paint(Color::Black);
robot.panel.len()
}
/// Solve part two.
fn part2(&self) -> String {
let mut robot = Robot::new(&self.brain);
robot.paint(Color::White);
robot.drawing()
}
}
fn main() {
let args = aoc::parse_args();
let puzzle = Puzzle::new(&args.input);
println!("{}", puzzle.part1());
println!("{}", puzzle.part2());
}