Skip to content

Commit 7e61ed5

Browse files
committed
Day 21
1 parent f4b1920 commit 7e61ed5

File tree

3 files changed

+235
-1
lines changed

3 files changed

+235
-1
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,9 @@ Solutions for [Advent of Code](https://adventofcode.com/) in [Rust](https://www.
3131
| [Day 18](./src/bin/18.rs) | `49.6µs` | `58.9µs` |
3232
| [Day 19](./src/bin/19.rs) | `204.0µs` | `693.5µs` |
3333
| [Day 20](./src/bin/20.rs) | `308.3µs` | `1.8ms` |
34+
| [Day 21](./src/bin/21.rs) | `11.0µs` | `109.7µs` |
3435

35-
**Total: 16.57ms**
36+
**Total: 16.69ms**
3637
<!--- benchmarking table --->
3738

3839
---

data/examples/21.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
029A
2+
980A
3+
179A
4+
456A
5+
379A

src/bin/21.rs

Lines changed: 228 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,228 @@
1+
use std::sync::atomic::AtomicUsize;
2+
3+
use itertools::Itertools;
4+
use memoize::{lazy_static::lazy_static, memoize};
5+
use rustc_hash::FxHashMap;
6+
7+
advent_of_code::solution!(21);
8+
9+
lazy_static! {
10+
static ref SUBST: FxHashMap<(char, char), String> = {
11+
[
12+
('^', '<', "v<A"),
13+
('^', '>', "v>A"),
14+
('^', 'A', ">A"),
15+
('^', 'v', "vA"),
16+
('^', '^', ""),
17+
('<', '^', ">^A"),
18+
('<', '>', ">>A"),
19+
('<', 'A', ">>^A"),
20+
('<', 'v', ">A"),
21+
('<', '<', ""),
22+
('>', '^', "<^A"),
23+
('>', '<', "<<A"),
24+
('>', 'A', "^A"),
25+
('>', 'v', "<A"),
26+
('>', '>', ""),
27+
('v', '^', "^A"),
28+
('v', '<', "<A"),
29+
('v', '>', ">A"),
30+
('v', 'A', "^>A"),
31+
('v', 'v', ""),
32+
('0', '1', "^<A"),
33+
('0', '2', "^A"),
34+
('0', '3', "^>A"),
35+
('0', '4', "^<^A"),
36+
('0', '5', "^^A"),
37+
('0', '6', "^^>A"),
38+
('0', '7', "^^^<A"),
39+
('0', '8', "^^^A"),
40+
('0', '9', "^^^>A"),
41+
('0', 'A', ">A"),
42+
('0', '0', ""),
43+
('1', '0', ">vA"),
44+
('1', '1', ""),
45+
('1', '2', ">A"),
46+
('1', '3', ">>A"),
47+
('1', '4', "^A"),
48+
('1', '5', "^>A"),
49+
('1', '6', "^>>A"),
50+
('1', '7', "^^A"),
51+
('1', '8', "^^>A"),
52+
('1', '9', "^^>>A"),
53+
('1', 'A', ">>vA"),
54+
('2', '0', "vA"),
55+
('2', '1', "<A"),
56+
('2', '2', ""),
57+
('2', '3', ">A"),
58+
('2', '4', "<^A"),
59+
('2', '5', "^A"),
60+
('2', '6', "^>A"),
61+
('2', '7', "<^^A"),
62+
('2', '8', "^^A"),
63+
('2', '9', "^^>A"),
64+
('2', 'A', "v>A"),
65+
('3', '0', "<vA"),
66+
('3', '1', "<<A"),
67+
('3', '2', "<A"),
68+
('3', '3', ""),
69+
('3', '4', "<<^A"),
70+
('3', '5', "<^A"),
71+
('3', '6', "^A"),
72+
('3', '7', "<<^^A"),
73+
('3', '8', "<^^A"),
74+
('3', '9', "^^A"),
75+
('3', 'A', "vA"),
76+
('4', '0', ">vvA"),
77+
('4', '1', "vA"),
78+
('4', '2', "v>A"),
79+
('4', '3', "v>>A"),
80+
('4', '4', ""),
81+
('4', '5', ">A"),
82+
('4', '6', ">>A"),
83+
('4', '7', "^A"),
84+
('4', '8', "^>A"),
85+
('4', '9', "^>>A"),
86+
('4', 'A', ">>vvA"),
87+
('5', '0', "vvA"),
88+
('5', '1', "<vA"),
89+
('5', '2', "vA"),
90+
('5', '3', "v>A"),
91+
('5', '4', "<A"),
92+
('5', '5', ""),
93+
('5', '6', ">A"),
94+
('5', '7', "<^A"),
95+
('5', '8', "^A"),
96+
('5', '9', "^>A"),
97+
('5', 'A', "vv>A"),
98+
('6', '0', "<vvA"),
99+
('6', '1', "<<vA"),
100+
('6', '2', "<vA"),
101+
('6', '3', "vA"),
102+
('6', '4', "<<A"),
103+
('6', '5', "<A"),
104+
('6', '6', ""),
105+
('6', '7', "<<^A"),
106+
('6', '8', "<^A"),
107+
('6', '9', "^A"),
108+
('6', 'A', "vvA"),
109+
('7', '0', ">vvvA"),
110+
('7', '1', "vvA"),
111+
('7', '2', "vv>A"),
112+
('7', '3', "vv>>A"),
113+
('7', '4', "vA"),
114+
('7', '5', "v>A"),
115+
('7', '6', "v>>A"),
116+
('7', '7', ""),
117+
('7', '8', ">A"),
118+
('7', '9', ">>A"),
119+
('7', 'A', ">>vvvA"),
120+
('8', '0', "vvvA"),
121+
('8', '1', "<vvA"),
122+
('8', '2', "vvA"),
123+
('8', '3', "vv>A"),
124+
('8', '4', "<vA"),
125+
('8', '5', "vA"),
126+
('8', '6', "v>A"),
127+
('8', '7', "<A"),
128+
('8', '8', ""),
129+
('8', '9', ">A"),
130+
('8', 'A', "vvv>A"),
131+
('9', '0', "<vvvA"),
132+
('9', '1', "<<vvA"),
133+
('9', '2', "<vvA"),
134+
('9', '3', "vvA"),
135+
('9', '4', "<<vA"),
136+
('9', '5', "<vA"),
137+
('9', '6', "vA"),
138+
('9', '7', "<<A"),
139+
('9', '8', "<A"),
140+
('9', '9', ""),
141+
('9', 'A', "vvvA"),
142+
('A', '^', "<A"),
143+
('A', '<', "v<<A"),
144+
('A', '>', "vA"),
145+
('A', '0', "<A"),
146+
('A', '1', "^<<A"),
147+
('A', '2', "<^A"),
148+
('A', '3', "^A"),
149+
('A', '4', "^^<<A"),
150+
('A', '5', "<^^A"),
151+
('A', '6', "^^A"),
152+
('A', '7', "^^^<<A"),
153+
('A', '8', "<^^^A"),
154+
('A', '9', "^^^A"),
155+
('A', 'A', ""),
156+
('A', 'v', "<vA"),
157+
]
158+
.iter()
159+
.map(|(from, to, rules)| ((*from, *to), rules.to_string()))
160+
.collect()
161+
};
162+
}
163+
164+
#[inline]
165+
fn parse_input<'a>(input: &'a str) -> impl Iterator<Item = (String, u64)> + 'a {
166+
input.lines().filter(|line| !line.is_empty()).map(|line| {
167+
let num = line.split_once('A').unwrap().0.parse::<u64>().unwrap();
168+
(line.to_string(), num)
169+
})
170+
}
171+
172+
#[memoize]
173+
fn get_length(_cb: usize, sequence: String, depth: usize) -> u64 {
174+
if sequence.is_empty() {
175+
return 1;
176+
}
177+
if depth == 0 {
178+
return sequence.len() as u64;
179+
}
180+
181+
std::iter::once('A')
182+
.chain(sequence.chars())
183+
.tuple_windows()
184+
.map(|pair| SUBST.get(&pair).expect("Invalid move"))
185+
.map(|next| get_length(_cb, next.to_owned(), depth - 1))
186+
.sum()
187+
}
188+
189+
// make benchmarks relevant
190+
static CACHE_BUSTER: AtomicUsize = AtomicUsize::new(0);
191+
192+
#[inline]
193+
fn solve(input: &str, depth: usize) -> u64 {
194+
let cache_buster = CACHE_BUSTER.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
195+
let codes = parse_input(input);
196+
codes
197+
.map(|(seq, num)| {
198+
let len = get_length(cache_buster, seq, depth);
199+
let complexity = len * num;
200+
complexity
201+
})
202+
.sum()
203+
}
204+
205+
pub fn part_one(input: &str) -> Option<u64> {
206+
Some(solve(input, 3))
207+
}
208+
209+
pub fn part_two(input: &str) -> Option<u64> {
210+
Some(solve(input, 25))
211+
}
212+
213+
#[cfg(test)]
214+
mod tests {
215+
use super::*;
216+
217+
#[test]
218+
fn test_part_one() {
219+
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
220+
assert_eq!(result, Some(126384));
221+
}
222+
223+
#[test]
224+
fn test_part_two() {
225+
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
226+
assert_eq!(result, Some(61952932092390));
227+
}
228+
}

0 commit comments

Comments
 (0)