1use crate::util::parse::*;
24use std::array::from_fn;
25
26pub struct Input {
27 state: usize,
28 steps: u32,
29 rules: Vec<[Rule; 2]>,
30}
31
32struct Rule {
33 next_state: usize,
34 next_tape: usize,
35 advance: bool,
36}
37
38impl Rule {
39 fn parse(block: &[&[u8]]) -> Self {
40 let next_tape = (block[0][22] - b'0') as usize;
41 let advance = block[1][27] == b'r';
42 let next_state = (block[2][26] - b'A') as usize;
43 Rule { next_state, next_tape, advance }
44 }
45}
46
47struct Skip {
48 next_state: usize,
49 next_tape: usize,
50 steps: u32,
51 ones: i32,
52 advance: bool,
53}
54
55pub fn parse(input: &str) -> Input {
57 let lines: Vec<_> = input.lines().map(str::as_bytes).collect();
58
59 let state = (lines[0][15] - b'A') as usize;
60 let steps = input.unsigned();
61 let rules: Vec<_> = lines[3..]
62 .chunks(10)
63 .map(|chunk| [Rule::parse(&chunk[2..5]), Rule::parse(&chunk[6..9])])
64 .collect();
65
66 Input { state, steps, rules }
67}
68
69pub fn part1(input: &Input) -> i32 {
70 let table: Vec<[Skip; 256]> = (0..input.rules.len())
74 .map(|state| from_fn(|tape| turing(&input.rules, state, tape, 100)))
75 .collect();
76
77 let mut state = input.state;
78 let mut remaining = input.steps;
79 let mut tape = 0;
80 let mut checksum = 0;
81 let mut left = Vec::new();
82 let mut right = Vec::new();
83
84 loop {
85 let Skip { next_state, next_tape, steps, ones, advance } = table[state][tape];
87
88 if steps > remaining {
90 let Skip { ones, .. } = turing(&input.rules, state, tape, remaining);
91 break checksum + ones;
92 }
93
94 state = next_state;
95 tape = next_tape;
96 remaining -= steps;
97 checksum += ones;
98
99 if advance {
103 left.push(tape & 0xf0);
104 tape = ((tape & 0xf) << 4) | right.pop().unwrap_or(0);
105 } else {
106 right.push(tape & 0xf);
107 tape = (tape >> 4) | left.pop().unwrap_or(0);
108 }
109 }
110}
111
112pub fn part2(_input: &Input) -> &'static str {
113 "n/a"
114}
115
116fn turing(rules: &[[Rule; 2]], mut state: usize, mut tape: usize, max_steps: u32) -> Skip {
118 let mut mask = 0b00001000;
119 let mut steps = 0;
120 let mut ones = 0;
121
122 while 0 < mask && mask < 128 && steps < max_steps {
125 let current = ((tape & mask) != 0) as usize;
126 let Rule { next_state, next_tape, advance } = rules[state][current];
127
128 if next_tape == 1 {
129 tape |= mask;
130 } else {
131 tape &= !mask;
132 }
133
134 if advance {
135 mask >>= 1;
136 } else {
137 mask <<= 1;
138 }
139
140 state = next_state;
141 steps += 1;
142 ones += next_tape as i32 - current as i32;
145 }
146
147 Skip { next_state: state, next_tape: tape, steps, ones, advance: mask == 0 }
148}