Skip to content

Commit 920d6f4

Browse files
committed
Add day 17
1 parent 3040d5b commit 920d6f4

File tree

4 files changed

+358
-1
lines changed

4 files changed

+358
-1
lines changed

benches/bench_days.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,4 @@ macro_rules! benches {
3838
};
3939
}
4040

41-
benches!(16);
41+
benches!(17);

src/day17.rs

Lines changed: 355 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,355 @@
1+
use core::str;
2+
3+
use aoc_runner_derive::aoc;
4+
5+
// 2 4: bst b=b%8
6+
// 1 5: bxl b=b^5
7+
// 7 5: cdv c=a/2^b
8+
// 1 6: bxl b=b^6
9+
// 0 3: adv a=a/8
10+
// 4 6: bxc b=b^c
11+
// 5 5: out out b
12+
// 3 0: jnz a!=0 -> 0
13+
14+
#[aoc(day17, part1)]
15+
pub fn part1(s: &str) -> &'static str {
16+
#[expect(unused_unsafe)]
17+
unsafe {
18+
inner_part1(s.as_bytes())
19+
}
20+
}
21+
22+
static mut RESULT: [u8; 128] = [0; 128];
23+
24+
// #[target_feature(enable = "avx2,bmi1,bmi2,cmpxchg16b,lzcnt,movbe,popcnt")]
25+
fn inner_part1(s: &[u8]) -> &'static str {
26+
let mut i = 13;
27+
28+
let mut a = (s[12] - b'0') as u32;
29+
while s[i] != b'\n' {
30+
a *= 10;
31+
a += (s[i] - b'0') as u32;
32+
i += 1;
33+
}
34+
35+
i += 14;
36+
let mut b = (s[i - 1] - b'0') as u32;
37+
while s[i] != b'\n' {
38+
b *= 10;
39+
b += (s[i] - b'0') as u32;
40+
i += 1;
41+
}
42+
43+
i += 14;
44+
let mut c = (s[i - 1] - b'0') as u32;
45+
while s[i] != b'\n' {
46+
c *= 10;
47+
c += (s[i] - b'0') as u32;
48+
i += 1;
49+
}
50+
51+
let code_start = i + 11;
52+
53+
let result_ptr = (&raw mut RESULT).cast::<u8>();
54+
let mut out_ptr = result_ptr;
55+
let result_ptr = result_ptr.cast_const();
56+
57+
let mut ip = 0;
58+
while ip * 2 + code_start < s.len() {
59+
let opcode = s[ip * 2 + code_start];
60+
let oper = s[ip * 2 + code_start + 2];
61+
62+
let get_lit = || (oper - b'0') as u32;
63+
let get_combo = || match oper {
64+
b'0' => 0,
65+
b'1' => 1,
66+
b'2' => 2,
67+
b'3' => 3,
68+
b'4' => a,
69+
b'5' => b,
70+
b'6' => c,
71+
_ => unreachable!(),
72+
};
73+
74+
match opcode {
75+
b'0' => {
76+
a = a / 2u32.pow(get_combo());
77+
ip += 2;
78+
}
79+
b'1' => {
80+
b = b ^ get_lit();
81+
ip += 2;
82+
}
83+
b'2' => {
84+
b = get_combo() % 8;
85+
ip += 2;
86+
}
87+
b'3' => {
88+
if a != 0 {
89+
ip = get_lit() as usize;
90+
} else {
91+
ip += 2;
92+
}
93+
}
94+
b'4' => {
95+
b = b ^ c;
96+
ip += 2;
97+
}
98+
b'5' => unsafe {
99+
out_ptr.write((get_combo() % 8) as u8 + b'0');
100+
out_ptr.offset(1).write(b',');
101+
102+
out_ptr = out_ptr.offset(2);
103+
ip += 2;
104+
},
105+
b'6' => {
106+
b = a / 2u32.pow(get_combo());
107+
ip += 2;
108+
}
109+
b'7' => {
110+
c = a / 2u32.pow(get_combo());
111+
ip += 2;
112+
}
113+
_ => unreachable!(),
114+
}
115+
}
116+
117+
let out_len = unsafe { out_ptr.offset_from(result_ptr) };
118+
119+
unsafe { str::from_utf8(&RESULT[..(out_len - 1) as usize]).unwrap() }
120+
}
121+
122+
const fn find_a_r(p: &[u64], x: u64, y: u64, pa: u64) -> Option<u64> {
123+
let Some((last, rest)) = p.split_last() else {
124+
return Some(pa / 8);
125+
};
126+
127+
let mut ia = 0;
128+
while ia < 8 {
129+
let a = pa | ia;
130+
131+
let b = a % 8;
132+
let b = b ^ x;
133+
let c = a >> b;
134+
let b = b ^ y;
135+
let b = b ^ c;
136+
if b % 8 == *last {
137+
if let Some(a) = find_a_r(rest, x, y, a * 8) {
138+
return Some(a);
139+
}
140+
}
141+
142+
ia += 1;
143+
}
144+
None
145+
}
146+
147+
const fn find_a(p: [u64; 16], x: u64, y: u64) -> u64 {
148+
match find_a_r(&p, x, y, 0) {
149+
Some(a) => a,
150+
None => 0, // :pray:,
151+
}
152+
}
153+
154+
static LUT: [u64; 8 * 8 * 8 * 8] = const {
155+
let mut lut = [0u64; 8 * 8 * 8 * 8];
156+
let mut x = 0;
157+
while x < 8 {
158+
let mut y = 0;
159+
while y < 8 {
160+
let mut z = 0;
161+
while z < 8 {
162+
lut[x as usize * 512 + y as usize * 64 + z as usize * 8 + 0] =
163+
find_a([2, 4, 1, x, 7, 5, 1, y, 4, z, 0, 3, 5, 5, 3, 0], x, y);
164+
lut[x as usize * 512 + y as usize * 64 + z as usize * 8 + 1] =
165+
find_a([2, 4, 1, x, 7, 5, 1, y, 4, z, 5, 5, 0, 3, 3, 0], x, y);
166+
167+
lut[x as usize * 512 + y as usize * 64 + z as usize * 8 + 2] =
168+
find_a([2, 4, 1, x, 7, 5, 1, y, 0, 3, 4, z, 5, 5, 3, 0], x, y);
169+
170+
lut[x as usize * 512 + y as usize * 64 + z as usize * 8 + 3] =
171+
find_a([2, 4, 1, x, 7, 5, 0, 3, 1, y, 4, z, 5, 5, 3, 0], x, y);
172+
173+
lut[x as usize * 512 + y as usize * 64 + z as usize * 8 + 4] =
174+
find_a([2, 4, 1, x, 7, 5, 0, 3, 4, z, 1, y, 5, 5, 3, 0], x, y);
175+
176+
lut[x as usize * 512 + y as usize * 64 + z as usize * 8 + 5] =
177+
find_a([2, 4, 1, x, 7, 5, 4, z, 1, y, 0, 3, 5, 5, 3, 0], x, y);
178+
lut[x as usize * 512 + y as usize * 64 + z as usize * 8 + 6] =
179+
find_a([2, 4, 1, x, 7, 5, 4, z, 1, y, 5, 5, 0, 3, 3, 0], x, y);
180+
181+
lut[x as usize * 512 + y as usize * 64 + z as usize * 8 + 7] =
182+
find_a([2, 4, 1, x, 7, 5, 4, z, 0, 3, 1, y, 5, 5, 3, 0], x, y);
183+
z += 1;
184+
}
185+
y += 1;
186+
}
187+
x += 1;
188+
}
189+
190+
lut
191+
};
192+
193+
#[aoc(day17, part2)]
194+
pub fn part2(s: &str) -> u64 {
195+
#[expect(unused_unsafe)]
196+
unsafe {
197+
inner_part2(s.as_bytes())
198+
}
199+
}
200+
201+
// #[target_feature(enable = "avx2,bmi1,bmi2,cmpxchg16b,lzcnt,movbe,popcnt")]
202+
fn inner_part2(s: &[u8]) -> u64 {
203+
let i = memchr::memchr(b',', s).unwrap() - 1;
204+
205+
let a = find_a(
206+
[
207+
(s[i + 0] - b'0') as u64,
208+
(s[i + 2] - b'0') as u64,
209+
(s[i + 4] - b'0') as u64,
210+
(s[i + 6] - b'0') as u64,
211+
(s[i + 8] - b'0') as u64,
212+
(s[i + 10] - b'0') as u64,
213+
(s[i + 12] - b'0') as u64,
214+
(s[i + 14] - b'0') as u64,
215+
(s[i + 16] - b'0') as u64,
216+
(s[i + 18] - b'0') as u64,
217+
(s[i + 20] - b'0') as u64,
218+
(s[i + 22] - b'0') as u64,
219+
(s[i + 24] - b'0') as u64,
220+
(s[i + 26] - b'0') as u64,
221+
(s[i + 28] - b'0') as u64,
222+
(s[i + 30] - b'0') as u64,
223+
],
224+
5,
225+
6,
226+
);
227+
228+
a
229+
230+
// let x = (s[i + 6] - b'0') as usize;
231+
232+
// let o1 = s[i + 12];
233+
// let o2 = s[i + 16];
234+
// let o3 = s[i + 20];
235+
// let o4 = s[i + 24];
236+
237+
// match (o1, o2, o3, o4) {
238+
// (b'1', b'4', b'0', b'5') => {
239+
// let y = (s[i + 14] - b'0') as usize;
240+
// let z = (s[i + 18] - b'0') as usize;
241+
// LUT[x * 512 + y * 64 + z * 8 + 0]
242+
// }
243+
// (b'1', b'4', b'5', b'0') => {
244+
// let y = (s[i + 14] - b'0') as usize;
245+
// let z = (s[i + 18] - b'0') as usize;
246+
// LUT[x * 512 + y * 64 + z * 8 + 1]
247+
// }
248+
// (b'1', b'0', b'4', b'5') => {
249+
// let y = (s[i + 14] - b'0') as usize;
250+
// let z = (s[i + 22] - b'0') as usize;
251+
// LUT[x * 512 + y * 64 + z * 8 + 0]
252+
// }
253+
// (b'0', b'1', b'4', b'5') => {
254+
// let y = (s[i + 18] - b'0') as usize;
255+
// let z = (s[i + 22] - b'0') as usize;
256+
// LUT[x * 512 + y * 64 + z * 8 + 0]
257+
// }
258+
// (b'0', b'4', b'1', b'5') => {
259+
// let y = (s[i + 18] - b'0') as usize;
260+
// let z = (s[i + 22] - b'0') as usize;
261+
// LUT[x * 512 + y * 64 + z * 8 + 0]
262+
// }
263+
// (b'4', b'1', b'0', b'5') => {
264+
// let y = (s[i + 18] - b'0') as usize;
265+
// let z = (s[i + 14] - b'0') as usize;
266+
// LUT[x * 512 + y * 64 + z * 8 + 0]
267+
// }
268+
// (b'4', b'1', b'5', b'0') => {
269+
// let y = (s[i + 18] - b'0') as usize;
270+
// let z = (s[i + 14] - b'0') as usize;
271+
// LUT[x * 512 + y * 64 + z * 8 + 0]
272+
// }
273+
// (b'4', b'0', b'1', b'5') => {
274+
// let y = (s[i + 22] - b'0') as usize;
275+
// let z = (s[i + 14] - b'0') as usize;
276+
// LUT[x * 512 + y * 64 + z * 8 + 0]
277+
// }
278+
// _ => unreachable!(),
279+
// }
280+
}
281+
282+
#[cfg(test)]
283+
mod tests {
284+
use super::*;
285+
286+
const EXAMPLE_1: &str = r"Register A: 0
287+
Register B: 0
288+
Register C: 9
289+
290+
Program: 2,6,5,5
291+
";
292+
293+
#[test]
294+
fn example1() {
295+
assert_eq!(part1(EXAMPLE_1), "1");
296+
}
297+
298+
const EXAMPLE_2: &str = r"Register A: 10
299+
Register B: 0
300+
Register C: 0
301+
302+
Program: 5,0,5,1,5,4
303+
";
304+
305+
#[test]
306+
fn example2() {
307+
assert_eq!(part1(EXAMPLE_2), "0,1,2");
308+
}
309+
310+
const EXAMPLE_3: &str = r"Register A: 2024
311+
Register B: 0
312+
Register C: 0
313+
314+
Program: 0,1,5,4,3,0
315+
";
316+
317+
#[test]
318+
fn example3() {
319+
assert_eq!(part1(EXAMPLE_3), "4,2,5,6,7,7,7,7,3,1,0");
320+
}
321+
322+
const EXAMPLE_4: &str = r"Register A: 0
323+
Register B: 29
324+
Register C: 0
325+
326+
Program: 1,7,5,0
327+
";
328+
#[test]
329+
fn example4() {
330+
assert_eq!(part1(EXAMPLE_4), "0");
331+
}
332+
333+
const EXAMPLE_5: &str = r"Register A: 0
334+
Register B: 2024
335+
Register C: 43690
336+
337+
Program: 4,0,5,1
338+
";
339+
#[test]
340+
fn example5() {
341+
assert_eq!(part1(EXAMPLE_5), "1");
342+
}
343+
344+
const EXAMPLE_PART1: &str = r"Register A: 729
345+
Register B: 0
346+
Register C: 0
347+
348+
Program: 0,1,5,4,3,0
349+
";
350+
351+
#[test]
352+
fn example_part1() {
353+
assert_eq!(part1(EXAMPLE_PART1), "4,6,3,5,6,3,5,2,1,0");
354+
}
355+
}

src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ pub mod day13;
1010
pub mod day14;
1111
pub mod day15;
1212
pub mod day16;
13+
pub mod day17;
1314
pub mod day2;
1415
pub mod day3;
1516
pub mod day4;

tests/test_days.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,5 @@ benches!(
4949
14 => ("220971520", "6355"),
5050
15 => ("1398947", "1397393"),
5151
16 => ("106512", "563"),
52+
17 => ("3,6,3,7,0,7,0,3,0", "136904920099226"),
5253
);

0 commit comments

Comments
 (0)