Skip to content

Commit

Permalink
day17: initial impl
Browse files Browse the repository at this point in the history
  • Loading branch information
Icerath committed Dec 18, 2024
1 parent babf6af commit ab36a55
Show file tree
Hide file tree
Showing 3 changed files with 130 additions and 6 deletions.
12 changes: 6 additions & 6 deletions benches/bench_today.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
use aoc_2024::day16::{part1, part2};
use aoc_2024::day17::{part1, part2};
use criterion::{criterion_group, criterion_main, Criterion};
use std::hint::black_box;

fn bench_part1(c: &mut Criterion) {
let input = include_str!("../input/day16.txt");
c.bench_function("day16_part1", |b| b.iter(|| part1(black_box(input))));
let input = include_str!("../input/day17.txt");
c.bench_function("day17_part1", |b| b.iter(|| part1(black_box(input))));
}

fn bench_part2(c: &mut Criterion) {
let input = include_str!("../input/day16.txt");
c.bench_function("day16_part2", |b| b.iter(|| part2(black_box(input))));
let input = include_str!("../input/day17.txt");
c.bench_function("day17_part2", |b| b.iter(|| part2(black_box(input))));
}

criterion_group!(benches, bench_part1, bench_part2,);
criterion_group!(benches, bench_part1, bench_part2);
criterion_main!(benches);
122 changes: 122 additions & 0 deletions src/day17.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#![expect(static_mut_refs, clippy::cast_possible_truncation)]

use std::hint::unreachable_unchecked;

pub fn part1(input: &str) -> &'static str {
unsafe { part1_inner(input.as_bytes()) }
}

unsafe fn parse(mut input: &[u8]) -> (u64, &[u8]) {
input = input.get_unchecked(12..);

let mut a = 0;
while *input.get_unchecked(0) != b'\n' {
a = a * 10 + (*input.get_unchecked(0) - b'0') as u64;
input = input.get_unchecked(1..);
}

let program = input.get_unchecked(1 + 38..);
(a, program)
}

unsafe fn part1_inner(input: &[u8]) -> &'static str {
static mut OUTPUT: [u8; 64] = [b','; 64];

let (mut a, program) = parse(input);
let (mut b, mut c, mut instruction_ptr) = (0, 0, 0);

let mut output_index = 0;
macro_rules! push_output {
($combo: expr) => {{
*OUTPUT.get_unchecked_mut(output_index) = ($combo) as u8 + b'0';
output_index += 2;
}};
}

while instruction_ptr < program.len() {
let literal = || (*program.get_unchecked(instruction_ptr + 2) - b'0') as u64;
let combo = || match literal() {
n @ 0..=3 => n,
4 => a,
5 => b,
6 => c,
_ => unreachable_unchecked(),
};

match *program.get_unchecked(instruction_ptr) {
b'0' => a >>= combo(),
b'1' => b ^= literal(),
b'2' => b = combo() & 7,
b'3' if a != 0 => instruction_ptr = (literal() * 2).wrapping_sub(4) as usize,
b'3' => {}
b'4' => b ^= c,
b'5' => push_output!(combo() & 7),
b'7' => c = a >> combo(),
_ => unreachable_unchecked(),
}

instruction_ptr = instruction_ptr.wrapping_add(4);
}
std::str::from_utf8_unchecked(OUTPUT.get_unchecked(..output_index - 1))
}

#[test]
fn test_part1() {
assert_eq!(part1(include_str!("../input/day17.txt")), "7,3,5,7,5,7,4,3,0");
}

#[test]
fn test_part2() {
assert_eq!(part2(include_str!("../input/day17.txt")), 105_734_774_294_938);
}

pub fn part2(input: &str) -> u64 {
unsafe { part2_inner(input.as_bytes()) }
}

unsafe fn part2_inner(input: &[u8]) -> u64 {
let (_, program) = unsafe { parse(input) };
recurse(program, program.len() - 2, 0).unwrap_unchecked()
}

unsafe fn recurse(program: &[u8], index: usize, mut a: u64) -> Option<u64> {
for _ in 0..8 {
if run(program, a) == (*program.get_unchecked(index) - b'0') as u64 {
let Some(index) = index.checked_sub(2) else { return Some(a) };
if let Some(a) = recurse(program, index, a << 3) {
return Some(a);
}
}
a += 1;
}
None
}

unsafe fn run(program: &[u8], mut a: u64) -> u64 {
let (mut b, mut c, mut instruction_ptr) = (0, 0, 0);
while instruction_ptr < program.len() {
let literal = || (*program.get_unchecked(instruction_ptr + 2) - b'0') as u64;
let combo = || match literal() {
n @ 0..=3 => n,
4 => a,
5 => b,
6 => c,
_ => unreachable_unchecked(),
};

match *program.get_unchecked(instruction_ptr) {
b'0' => a >>= combo(),
b'1' => b ^= literal(),
b'2' => b = combo() % 8,
b'3' if a != 0 => instruction_ptr = (literal() * 2).wrapping_sub(4) as usize,
b'3' => {}
b'4' => b ^= c,
b'5' => return combo() % 8,
b'7' => c = a >> combo(),
_ => unreachable_unchecked(),
}

instruction_ptr = instruction_ptr.wrapping_add(4);
}
unreachable_unchecked()
}
2 changes: 2 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#![feature(array_windows)]
#![feature(portable_simd)]
#![feature(iter_array_chunks)]

pub mod day1;
pub mod day10;
pub mod day11;
Expand All @@ -9,6 +10,7 @@ pub mod day13;
pub mod day14;
pub mod day15;
pub mod day16;
pub mod day17;
pub mod day2;
pub mod day3;
pub mod day4;
Expand Down

0 comments on commit ab36a55

Please sign in to comment.