-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathday19.rs
156 lines (123 loc) · 3.75 KB
/
day19.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
146
147
148
149
150
151
152
153
154
155
156
//! [Day 19: Tractor Beam](https://adventofcode.com/2019/day/19)
use intcode::{Computer, State};
const SQUARE: i64 = 100;
const SQUARE_USIZE: usize = 100;
const N: i64 = 50;
struct Scanner {
xmax: i64,
x1: i64,
x2: i64,
drone: Computer,
}
impl Scanner {
fn new(drone: &Computer, xmax: i64) -> Self {
Self {
xmax,
x1: 0,
x2: -1,
drone: drone.clone(),
}
}
fn scan_cell(&mut self, x: i64, y: i64) -> i64 {
self.drone.reset();
self.drone.push(x);
self.drone.push(y);
if let State::Output(num) = self.drone.run() {
num
} else {
panic!("failed to scan cell {x},{y}")
}
}
fn scan_row(&mut self, y: i64) -> Option<i64> {
let mut x1 = self.x1;
while self.scan_cell(x1, y) == 0 && x1 < self.xmax {
x1 += 1;
}
if x1 == self.xmax {
return None;
}
self.x1 = x1;
if x1 > self.x2 {
self.x2 = x1;
}
while self.x2 < self.xmax && self.scan_cell(self.x2, y) == 1 {
self.x2 += 1;
}
Some(self.x2 - self.x1)
}
}
struct Puzzle {
drone: Computer,
}
impl Puzzle {
/// Initialize from the puzzle input.
fn new(data: &str) -> Self {
Self {
drone: Computer::load(data),
}
}
/// Solve part one.
fn part1(&self) -> i64 {
let mut scanner = Scanner::new(&self.drone, N);
(0..50).filter_map(|y| scanner.scan_row(y)).sum()
}
/// Solve part two.
fn part2(&self) -> i64 {
let mut scanner = Scanner::new(&self.drone, 50);
for y in 0..N {
scanner.scan_row(y);
}
let mut grid = Vec::new();
scanner.xmax = 10000;
for y in N..10000 {
scanner.scan_row(y);
let row = (y, scanner.x1, scanner.x2);
grid.push(row);
if y < N + SQUARE {
continue;
}
// let's consider the square OABC:
// ................#################.......
// .................########O--------A..... <= 100th row before
// ..................#######| |#....
// ...................######| |###..
// ....................#####| |#####
// .....................####| |#####
// .....................####| |#####
// ......................###| |#####
// .......................##| |#####
// ........................#| |#####
// .........................C--------B##### <- current row
// ..........................##############
// - A should be at the very right of the 100th row before the current one
// - B should be at the very left of the current row
// - and, obviously, all points should be into the beam
let upper_row = grid[grid.len() - SQUARE_USIZE];
let y_b = row.0;
// let y_c = row.0;
let y_o = upper_row.0;
// let y_a = upper_row.0;
// the scan should not miss any row
assert_eq!(y_b - y_o + 1, SQUARE);
let x_a = upper_row.2;
let x_c = x_a - SQUARE;
let x_o = x_a - SQUARE;
let x_b = x_a;
if x_o < upper_row.1 || x_c < row.1 || x_b > row.2 {
continue;
}
return x_o * 10000 + y_o;
}
0
}
}
/// # Panics
#[must_use]
pub fn solve(data: &str) -> (i64, i64) {
let puzzle = Puzzle::new(data);
(puzzle.part1(), puzzle.part2())
}
pub fn main() {
let args = aoc::parse_args();
args.run(solve);
}