|
| 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