Skip to content

Commit

Permalink
aoc2024/day17: Add solution
Browse files Browse the repository at this point in the history
Signed-off-by: Andrej Orsula <orsula.andrej@gmail.com>
  • Loading branch information
AndrejOrsula committed Dec 17, 2024
1 parent 5286df0 commit e9ad956
Show file tree
Hide file tree
Showing 4 changed files with 223 additions and 21 deletions.
40 changes: 20 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,26 +15,26 @@ My solutions to [Advent of Code](https://adventofcode.com) puzzles.

> All benchmarks are run on a *Dell Precision 5550* laptop with an *Intel Core i7-10875H* CPU.
| D | Puzzle | Code | Part 1 Performance | Part 2 Performance |
| :---: | ------------------------------------------------------------ | :------------------------------: | :----------------: | :----------------: |
| 1 | [Historian Hysteria](https://adventofcode.com/2024/day/1) | [day1.rs](aoc2024/src/day1.rs) | 92.26 µs | 69.56 µs |
| 2 | [Red-Nosed Reports](https://adventofcode.com/2024/day/2) | [day2.rs](aoc2024/src/day2.rs) | 67.96 µs | 141.4 µs |
| 3 | [Mull It Over](https://adventofcode.com/2024/day/3) | [day3.rs](aoc2024/src/day3.rs) | 81.17 µs | 79.13 µs |
| 4 | [Ceres Search](https://adventofcode.com/2024/day/4) | [day4.rs](aoc2024/src/day4.rs) | 257.6 µs | 142.3 µs |
| 5 | [Print Queue](https://adventofcode.com/2024/day/5) | [day5.rs](aoc2024/src/day5.rs) | 98.64 µs | 133.9 µs |
| 6 | [Guard Gallivant](https://adventofcode.com/2024/day/6) | [day6.rs](aoc2024/src/day6.rs) | 39.48 µs | 6.768 ms |
| 7 | [Bridge Repair](https://adventofcode.com/2024/day/7) | [day7.rs](aoc2024/src/day7.rs) | 824.2 µs | 49.06 ms |
| 8 | [Resonant Collinearity](https://adventofcode.com/2024/day/8) | [day8.rs](aoc2024/src/day8.rs) | 40.13 µs | 36.43 µs |
| 9 | [Disk Fragmenter](https://adventofcode.com/2024/day/9) | [day9.rs](aoc2024/src/day9.rs) | 186.2 µs | 134.5 ms |
| 10 | [Hoof It](https://adventofcode.com/2024/day/10) | [day10.rs](aoc2024/src/day10.rs) | 210.9 µs | 82.03 µs |
| 11 | [Plutonian Pebbles](https://adventofcode.com/2024/day/11) | [day11.rs](aoc2024/src/day11.rs) | 215.0 µs | 5.208 ms |
| 12 | [Garden Groups](https://adventofcode.com/2024/day/12) | [day12.rs](aoc2024/src/day12.rs) | 1.319 ms | 1.974 ms |
| 13 | [Claw Contraption](https://adventofcode.com/2024/day/13) | [day13.rs](aoc2024/src/day13.rs) | 87.33 µs | 72.88 µs |
| 14 | [Restroom Redoubt](https://adventofcode.com/2024/day/14) | [day14.rs](aoc2024/src/day14.rs) | 35.37 µs | 20.60 ms |
| 15 | [Warehouse Woes](https://adventofcode.com/2024/day/15) | [day15.rs](aoc2024/src/day15.rs) | 234.6 µs | 241.8 µs |
| 16 | [Reindeer Maze](https://adventofcode.com/2024/day/16) | [day16.rs](aoc2024/src/day16.rs) | 5.066 ms | 5.353 ms |

<!-- | 17 | [TODO](https://adventofcode.com/2024/day/17) | [day17.rs](aoc2024/src/day17.rs) | | | -->
| D | Puzzle | Code | Part 1 Performance | Part 2 Performance |
| :---: | -------------------------------------------------------------- | :------------------------------: | :----------------: | :----------------: |
| 1 | [Historian Hysteria](https://adventofcode.com/2024/day/1) | [day1.rs](aoc2024/src/day1.rs) | 92.26 µs | 69.56 µs |
| 2 | [Red-Nosed Reports](https://adventofcode.com/2024/day/2) | [day2.rs](aoc2024/src/day2.rs) | 67.96 µs | 141.4 µs |
| 3 | [Mull It Over](https://adventofcode.com/2024/day/3) | [day3.rs](aoc2024/src/day3.rs) | 81.17 µs | 79.13 µs |
| 4 | [Ceres Search](https://adventofcode.com/2024/day/4) | [day4.rs](aoc2024/src/day4.rs) | 257.6 µs | 142.3 µs |
| 5 | [Print Queue](https://adventofcode.com/2024/day/5) | [day5.rs](aoc2024/src/day5.rs) | 98.64 µs | 133.9 µs |
| 6 | [Guard Gallivant](https://adventofcode.com/2024/day/6) | [day6.rs](aoc2024/src/day6.rs) | 39.48 µs | 6.768 ms |
| 7 | [Bridge Repair](https://adventofcode.com/2024/day/7) | [day7.rs](aoc2024/src/day7.rs) | 824.2 µs | 49.06 ms |
| 8 | [Resonant Collinearity](https://adventofcode.com/2024/day/8) | [day8.rs](aoc2024/src/day8.rs) | 40.13 µs | 36.43 µs |
| 9 | [Disk Fragmenter](https://adventofcode.com/2024/day/9) | [day9.rs](aoc2024/src/day9.rs) | 186.2 µs | 134.5 ms |
| 10 | [Hoof It](https://adventofcode.com/2024/day/10) | [day10.rs](aoc2024/src/day10.rs) | 210.9 µs | 82.03 µs |
| 11 | [Plutonian Pebbles](https://adventofcode.com/2024/day/11) | [day11.rs](aoc2024/src/day11.rs) | 215.0 µs | 5.208 ms |
| 12 | [Garden Groups](https://adventofcode.com/2024/day/12) | [day12.rs](aoc2024/src/day12.rs) | 1.319 ms | 1.974 ms |
| 13 | [Claw Contraption](https://adventofcode.com/2024/day/13) | [day13.rs](aoc2024/src/day13.rs) | 87.33 µs | 72.88 µs |
| 14 | [Restroom Redoubt](https://adventofcode.com/2024/day/14) | [day14.rs](aoc2024/src/day14.rs) | 35.37 µs | 20.60 ms |
| 15 | [Warehouse Woes](https://adventofcode.com/2024/day/15) | [day15.rs](aoc2024/src/day15.rs) | 234.6 µs | 241.8 µs |
| 16 | [Reindeer Maze](https://adventofcode.com/2024/day/16) | [day16.rs](aoc2024/src/day16.rs) | 5.066 ms | 5.353 ms |
| 17 | [Chronospatial Computer](https://adventofcode.com/2024/day/17) | [day17.rs](aoc2024/src/day17.rs) | 2.124 µs | 26.82 µs |

<!-- | 18 | [TODO](https://adventofcode.com/2024/day/18) | [day18.rs](aoc2024/src/day18.rs) | | | -->
<!-- | 19 | [TODO](https://adventofcode.com/2024/day/19) | [day19.rs](aoc2024/src/day19.rs) | | | -->
<!-- | 20 | [TODO](https://adventofcode.com/2024/day/20) | [day20.rs](aoc2024/src/day20.rs) | | | -->
Expand Down
5 changes: 5 additions & 0 deletions aoc2024/input/2024/day17.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
Register A: 56256477
Register B: 0
Register C: 0

Program: 2,4,1,1,7,5,1,5,0,3,4,3,5,5,3,0
197 changes: 197 additions & 0 deletions aoc2024/src/day17.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
use aoc_runner_derive::aoc;
use itertools::Itertools;

#[aoc(day17, part1)]
#[must_use]
pub fn part1(input: &str) -> String {
let mut prog = Program::parse(input);
std::iter::from_fn(|| prog.step()).join(",")
}

#[aoc(day17, part2)]
#[must_use]
pub fn part2(input: &str) -> usize {
Program::parse_instructions(input, 0)
.instructions
.into_iter()
.rev()
.fold(
smallvec::SmallVec::<[usize; 32]>::from_elem(0, 1),
|queue, instruction| {
queue
.into_iter()
.flat_map(move |i| {
(0..8).filter_map(move |j| {
let reg_a = j | (i << 3);
Program::parse_instructions(input, reg_a)
.step()
.is_some_and(|i| i == instruction as usize)
.then_some(reg_a)
})
})
.collect()
},
)[0]
}

#[derive(Debug)]
struct Program {
instructions: smallvec::SmallVec<[u8; 16]>,
reg_a: usize,
reg_b: usize,
reg_c: usize,
pointer: usize,
}

impl Program {
#[inline]
fn parse(input: &str) -> Program {
let (registers, instructions) = unsafe { input.split_once("\n\n").unwrap_unchecked() };
let reg_a = registers
.bytes()
.skip(12)
.take_while(u8::is_ascii_digit)
.fold(0, |num, b| unsafe {
10_usize
.unchecked_mul(num)
.unchecked_add(b.unchecked_sub(b'0') as usize)
});
let instructions = instructions
.bytes()
.skip(9)
.step_by(2)
.map(|b| unsafe { b.unchecked_sub(b'0') })
.collect();

Self {
instructions,
reg_a,
reg_b: 0,
reg_c: 0,
pointer: 0,
}
}

#[inline]
fn parse_instructions(input: &str, reg_a: usize) -> Program {
let (_, instructions) = unsafe { input.split_once("\n\n").unwrap_unchecked() };
let instructions = instructions
.bytes()
.skip(9)
.step_by(2)
.map(|b| unsafe { b.unchecked_sub(b'0') })
.collect();

Self {
instructions,
reg_a,
reg_b: 0,
reg_c: 0,
pointer: 0,
}
}

#[inline]
fn step(&mut self) -> Option<usize> {
while self.pointer < self.instructions.len() {
match self.instructions[self.pointer] {
0 => {
self.reg_a >>= match self.instructions[unsafe { self.pointer.unchecked_add(1) }]
{
instruction @ 0..4 => instruction as usize,
4 => self.reg_a,
5 => self.reg_b,
6 => self.reg_c,
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
1 => {
self.reg_b ^=
self.instructions[unsafe { self.pointer.unchecked_add(1) }] as usize;
}
2 => {
self.reg_b = match self.instructions[unsafe { self.pointer.unchecked_add(1) }] {
instruction @ 0..4 => instruction as usize,
4 => self.reg_a,
5 => self.reg_b,
6 => self.reg_c,
_ => unsafe { std::hint::unreachable_unchecked() },
} % 8;
}
3 => {
if self.reg_a != 0 {
self.pointer =
self.instructions[unsafe { self.pointer.unchecked_add(1) }] as usize;
continue;
}
}
4 => self.reg_b ^= self.reg_c,
5 => {
let i = match self.instructions[unsafe { self.pointer.unchecked_add(1) }] {
instruction @ 0..4 => instruction as usize,
4 => self.reg_a,
5 => self.reg_b,
6 => self.reg_c,
_ => unsafe { std::hint::unreachable_unchecked() },
} % 8;
self.pointer = unsafe { self.pointer.unchecked_add(2) };
return Some(i);
}
6 => {
self.reg_b = self.reg_a
>> match self.instructions[unsafe { self.pointer.unchecked_add(1) }] {
instruction @ 0..4 => instruction as usize,
4 => self.reg_a,
5 => self.reg_b,
6 => self.reg_c,
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
7 => {
self.reg_c = self.reg_a
>> match self.instructions[unsafe { self.pointer.unchecked_add(1) }] {
instruction @ 0..4 => instruction as usize,
4 => self.reg_a,
5 => self.reg_b,
6 => self.reg_c,
_ => unsafe { std::hint::unreachable_unchecked() },
}
}
_ => unsafe { std::hint::unreachable_unchecked() },
}
self.pointer = unsafe { self.pointer.unchecked_add(2) };
}
None
}
}

#[cfg(test)]
mod tests {
use super::*;
use indoc::indoc;

const SAMPLE1: &str = indoc! {"
Register A: 729
Register B: 0
Register C: 0
Program: 0,1,5,4,3,0
"};
const SAMPLE2: &str = indoc! {"
Register A: 2024
Register B: 0
Register C: 0
Program: 0,3,5,4,3,0
"};

#[test]
pub fn part1_example() {
assert_eq!(part1(SAMPLE1), "4,6,3,5,6,3,5,2,1,0");
}

#[test]
pub fn part2_example() {
assert_eq!(part2(SAMPLE2), 117_440);
}
}
2 changes: 1 addition & 1 deletion aoc2024/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub mod day13;
pub mod day14;
pub mod day15;
pub mod day16;
// pub mod day17;
pub mod day17;
// pub mod day18;
// pub mod day19;

Expand Down

0 comments on commit e9ad956

Please sign in to comment.