1use crate::util::hash::*;
13use crate::util::parse::*;
14use std::iter::repeat_with;
15
16const UPPER: u128 = u128::MAX << 64;
17const LOWER: u128 = u128::MAX >> 64;
18
19pub struct Input {
20 state: usize,
21 steps: u32,
22 rules: Vec<[Rule; 2]>,
23}
24
25struct Rule {
26 next_state: usize,
27 next_tape: bool,
28 advance: bool,
29}
30
31impl Rule {
32 fn parse(block: &[&[u8]]) -> Self {
33 let next_tape = block[0][22] == b'1';
34 let advance = block[1][27] == b'r';
35 let next_state = (block[2][26] - b'A') as usize;
36 Rule { next_state, next_tape, advance }
37 }
38}
39
40struct Skip {
41 next_state: usize,
42 next_tape: u128,
43 steps: u32,
44 advance: bool,
45}
46
47pub fn parse(input: &str) -> Input {
49 let lines: Vec<_> = input.lines().map(str::as_bytes).collect();
50
51 let state = (lines[0][15] - b'A') as usize;
52 let steps = input.unsigned();
53 let rules: Vec<_> = lines[3..]
54 .chunks(10)
55 .map(|chunk| [Rule::parse(&chunk[2..5]), Rule::parse(&chunk[6..9])])
56 .collect();
57
58 Input { state, steps, rules }
59}
60
61pub fn part1(input: &Input) -> u32 {
62 let mut state = input.state;
63 let mut remaining = input.steps;
64 let mut tape = 0;
65 let mut left = Vec::new();
66 let mut right = Vec::new();
67 let mut cache: Vec<_> = repeat_with(FastMap::new).take(input.rules.len()).collect();
68
69 loop {
70 let Skip { next_state, next_tape, steps, advance } = *cache[state]
72 .entry(tape)
73 .or_insert_with(|| turing(&input.rules, state, tape, u32::MAX));
74
75 if steps > remaining {
77 let Skip { next_tape, .. } = turing(&input.rules, state, tape, remaining);
78 left.push(next_tape);
79 break;
80 }
81
82 state = next_state;
83 tape = next_tape;
84 remaining -= steps;
85
86 if advance {
90 left.push(tape & UPPER);
91 tape = (tape << 64) | right.pop().unwrap_or(0);
92 } else {
93 right.push(tape & LOWER);
94 tape = (tape >> 64) | left.pop().unwrap_or(0);
95 }
96 }
97
98 left.into_iter().chain(right).map(u128::count_ones).sum()
99}
100
101pub fn part2(_input: &Input) -> &'static str {
102 "n/a"
103}
104
105#[inline]
107fn turing(rules: &[[Rule; 2]], mut state: usize, mut tape: u128, max_steps: u32) -> Skip {
108 let mut mask = 1 << 63;
109 let mut steps = 0;
110
111 while 0 < mask && mask < (1 << 127) && steps < max_steps {
114 let current = usize::from(tape & mask != 0);
115 let rule = &rules[state][current];
116
117 tape = if rule.next_tape { tape | mask } else { tape & !mask };
118 mask = if rule.advance { mask >> 1 } else { mask << 1 };
119 state = rule.next_state;
120 steps += 1;
121 }
122
123 Skip { next_state: state, next_tape: tape, steps, advance: mask == 0 }
124}