Skip to content

Commit 9145f98

Browse files
committed
2018 day 10
1 parent c3b35f8 commit 9145f98

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

crates/year2018/src/day10.rs

Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
use utils::point::Point2D;
2+
use utils::prelude::*;
3+
4+
/// Recognizing text formed by converging points.
5+
#[derive(Clone, Debug)]
6+
pub struct Day10 {
7+
message: String,
8+
seconds: u32,
9+
}
10+
11+
impl Day10 {
12+
pub fn new(input: &str, _: InputType) -> Result<Self, InputError> {
13+
let point = parser::i32()
14+
.with_prefix(parser::take_while(|&x| x == b' '))
15+
.repeat_n(b',')
16+
.map(Point2D::from);
17+
18+
let mut points = point
19+
.with_prefix("position=<")
20+
.with_suffix("> velocity=<")
21+
.then(point)
22+
.with_suffix(">")
23+
.repeat(parser::eol(), 2)
24+
.parse_complete(input)?;
25+
26+
let mut seconds = 0;
27+
let (mut last_x_diff, mut last_y_diff) = (i32::MAX, i32::MAX);
28+
let message = 'time: loop {
29+
let (mut min_x, mut max_x) = (i32::MAX, i32::MIN);
30+
let (mut min_y, mut min_y_vel, mut max_y, mut max_y_vel) = (i32::MAX, 0, i32::MIN, 0);
31+
for (p, v) in &points {
32+
min_x = min_x.min(p.x);
33+
max_x = max_x.max(p.x);
34+
35+
if p.y < min_y {
36+
min_y = p.y;
37+
min_y_vel = v.y;
38+
}
39+
if p.y > max_y {
40+
max_y = p.y;
41+
max_y_vel = v.y;
42+
}
43+
}
44+
45+
let (x_diff, y_diff) = (max_x.saturating_sub(min_x), max_y.saturating_sub(min_y));
46+
if x_diff > last_x_diff
47+
|| y_diff > last_y_diff
48+
|| (x_diff == last_x_diff && y_diff == last_y_diff)
49+
{
50+
return Err(InputError::new(input, 0, "points never converge"));
51+
}
52+
(last_x_diff, last_y_diff) = (x_diff, y_diff);
53+
54+
// Letters are 6 wide and 10 tall, with 2 wide gaps between them
55+
if y_diff != 9 || x_diff % 8 != 5 {
56+
let advance_by = if y_diff >= 10 && min_y_vel.saturating_sub(max_y_vel) > 0 {
57+
((y_diff - 9) / min_y_vel.saturating_sub(max_y_vel)).max(1)
58+
} else {
59+
1
60+
};
61+
62+
for (p, v) in points.iter_mut() {
63+
*p += *v * advance_by;
64+
}
65+
seconds += advance_by as u32;
66+
67+
continue;
68+
}
69+
70+
let len = ((max_x - min_x + 3) / 8) as usize;
71+
let mut letters = vec![0u64; len];
72+
for (p, _) in points.iter() {
73+
if (p.x - min_x) % 8 >= 6 {
74+
// Point where there should be a 2-wide gap
75+
continue 'time;
76+
}
77+
78+
letters[(p.x - min_x) as usize / 8] |=
79+
1 << (59 - ((p.x - min_x) % 8 + 6 * (p.y - min_y)));
80+
}
81+
break letters.into_iter().map(Self::ocr).collect::<String>();
82+
};
83+
84+
Ok(Self { message, seconds })
85+
}
86+
87+
fn ocr(letter: u64) -> char {
88+
// ## ##### #### ###### ###### #### # # ### # # # # #
89+
// # # # # # # # # # # # # # # # # ## #
90+
// # # # # # # # # # # # # # # ## #
91+
// # # # # # # # # # # # # # # # # #
92+
// # # ##### # ##### ##### # ###### # ## # # # #
93+
// ###### # # # # # # ### # # # ## # # # #
94+
// # # # # # # # # # # # # # # # # # #
95+
// # # # # # # # # # # # # # # # # # ##
96+
// # # # # # # # # # ## # # # # # # # # ##
97+
// # # ##### #### ###### # ### # # # ### # # ###### # #
98+
//
99+
// ##### ##### # # ######
100+
// # # # # # # #
101+
// # # # # # # #
102+
// # # # # # # #
103+
// ##### ##### ## #
104+
// # # # ## #
105+
// # # # # # #
106+
// # # # # # #
107+
// # # # # # #
108+
// # # # # # ######
109+
match letter {
110+
//000000111111222222333333444444555555666666777777888888999999
111+
0b001100010010100001100001100001111111100001100001100001100001 => 'A',
112+
0b111110100001100001100001111110100001100001100001100001111110 => 'B',
113+
0b011110100001100000100000100000100000100000100000100001011110 => 'C',
114+
0b111111100000100000100000111110100000100000100000100000111111 => 'E',
115+
0b111111100000100000100000111110100000100000100000100000100000 => 'F',
116+
0b011110100001100000100000100000100111100001100001100011011101 => 'G',
117+
0b100001100001100001100001111111100001100001100001100001100001 => 'H',
118+
0b000111000010000010000010000010000010000010100010100010011100 => 'J',
119+
0b100001100010100100101000110000110000101000100100100010100001 => 'K',
120+
0b100000100000100000100000100000100000100000100000100000111111 => 'L',
121+
0b100001110001110001101001101001100101100101100011100011100001 => 'N',
122+
0b111110100001100001100001111110100000100000100000100000100000 => 'P',
123+
0b111110100001100001100001111110100100100010100010100001100001 => 'R',
124+
0b100001100001010010010010001100001100010010010010100001100001 => 'X',
125+
0b111111000001000001000010000100001000010000100000100000111111 => 'Z',
126+
_ => Self::unknown_letter(letter),
127+
}
128+
}
129+
130+
#[cold]
131+
fn unknown_letter(letter: u64) -> char {
132+
let mut display = String::new();
133+
for b in (0..60).rev() {
134+
display.push(if letter & (1 << b) == 0 { ' ' } else { '#' });
135+
if b % 6 == 0 {
136+
display.push('\n');
137+
}
138+
}
139+
panic!("unknown letter {letter:#062b}:\n{display}");
140+
}
141+
142+
#[must_use]
143+
pub fn part1(&self) -> &str {
144+
&self.message
145+
}
146+
147+
#[must_use]
148+
pub fn part2(&self) -> u32 {
149+
self.seconds
150+
}
151+
}
152+
153+
examples!(Day10 -> (&'static str, u32) []);

crates/year2018/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@ utils::year!(2018 => year2018, ${
1111
7 => day07::Day07,
1212
8 => day08::Day08,
1313
9 => day09::Day09,
14+
10 => day10::Day10,
1415
});

0 commit comments

Comments
 (0)