From 96c6cb8a76160977077bdddc66f271ee9988be67 Mon Sep 17 00:00:00 2001 From: pareronia <49491686+pareronia@users.noreply.github.com> Date: Tue, 17 Dec 2024 20:33:08 +0100 Subject: [PATCH] AoC 2024 Day 17 - rust --- README.md | 2 +- src/main/rust/AoC2024_17/Cargo.toml | 7 + src/main/rust/AoC2024_17/src/main.rs | 237 +++++++++++++++++++++++++++ src/main/rust/Cargo.lock | 7 + 4 files changed, 252 insertions(+), 1 deletion(-) create mode 100644 src/main/rust/AoC2024_17/Cargo.toml create mode 100644 src/main/rust/AoC2024_17/src/main.rs diff --git a/README.md b/README.md index 59cfd30..1171a15 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ | ---| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | | python3 | [✓](src/main/python/AoC2024_01.py) | [✓](src/main/python/AoC2024_02.py) | [✓](src/main/python/AoC2024_03.py) | [✓](src/main/python/AoC2024_04.py) | [✓](src/main/python/AoC2024_05.py) | [✓](src/main/python/AoC2024_06.py) | [✓](src/main/python/AoC2024_07.py) | [✓](src/main/python/AoC2024_08.py) | [✓](src/main/python/AoC2024_09.py) | [✓](src/main/python/AoC2024_10.py) | [✓](src/main/python/AoC2024_11.py) | [✓](src/main/python/AoC2024_12.py) | [✓](src/main/python/AoC2024_13.py) | [✓](src/main/python/AoC2024_14.py) | [✓](src/main/python/AoC2024_15.py) | [✓](src/main/python/AoC2024_16.py) | [✓](src/main/python/AoC2024_17.py) | | | | | | | | | | java | [✓](src/main/java/AoC2024_01.java) | [✓](src/main/java/AoC2024_02.java) | [✓](src/main/java/AoC2024_03.java) | [✓](src/main/java/AoC2024_04.java) | [✓](src/main/java/AoC2024_05.java) | [✓](src/main/java/AoC2024_06.java) | [✓](src/main/java/AoC2024_07.java) | [✓](src/main/java/AoC2024_08.java) | | [✓](src/main/java/AoC2024_10.java) | [✓](src/main/java/AoC2024_11.java) | [✓](src/main/java/AoC2024_12.java) | | [✓](src/main/java/AoC2024_14.java) | [✓](src/main/java/AoC2024_15.java) | | | | | | | | | | | -| rust | [✓](src/main/rust/AoC2024_01/src/main.rs) | [✓](src/main/rust/AoC2024_02/src/main.rs) | [✓](src/main/rust/AoC2024_03/src/main.rs) | [✓](src/main/rust/AoC2024_04/src/main.rs) | [✓](src/main/rust/AoC2024_05/src/main.rs) | [✓](src/main/rust/AoC2024_06/src/main.rs) | [✓](src/main/rust/AoC2024_07/src/main.rs) | [✓](src/main/rust/AoC2024_08/src/main.rs) | | [✓](src/main/rust/AoC2024_10/src/main.rs) | | | [✓](src/main/rust/AoC2024_13/src/main.rs) | [✓](src/main/rust/AoC2024_14/src/main.rs) | [✓](src/main/rust/AoC2024_15/src/main.rs) | [✓](src/main/rust/AoC2024_16/src/main.rs) | | | | | | | | | | +| rust | [✓](src/main/rust/AoC2024_01/src/main.rs) | [✓](src/main/rust/AoC2024_02/src/main.rs) | [✓](src/main/rust/AoC2024_03/src/main.rs) | [✓](src/main/rust/AoC2024_04/src/main.rs) | [✓](src/main/rust/AoC2024_05/src/main.rs) | [✓](src/main/rust/AoC2024_06/src/main.rs) | [✓](src/main/rust/AoC2024_07/src/main.rs) | [✓](src/main/rust/AoC2024_08/src/main.rs) | | [✓](src/main/rust/AoC2024_10/src/main.rs) | | | [✓](src/main/rust/AoC2024_13/src/main.rs) | [✓](src/main/rust/AoC2024_14/src/main.rs) | [✓](src/main/rust/AoC2024_15/src/main.rs) | [✓](src/main/rust/AoC2024_16/src/main.rs) | [✓](src/main/rust/AoC2024_17/src/main.rs) | | | | | | | | | ## 2023 diff --git a/src/main/rust/AoC2024_17/Cargo.toml b/src/main/rust/AoC2024_17/Cargo.toml new file mode 100644 index 0000000..6b5f6bc --- /dev/null +++ b/src/main/rust/AoC2024_17/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "AoC2024_17" +version = "0.1.0" +edition = "2021" + +[dependencies] +aoc = { path = "../aoc" } diff --git a/src/main/rust/AoC2024_17/src/main.rs b/src/main/rust/AoC2024_17/src/main.rs new file mode 100644 index 0000000..c0a8b0d --- /dev/null +++ b/src/main/rust/AoC2024_17/src/main.rs @@ -0,0 +1,237 @@ +// #![allow(non_snake_case)] + +use aoc::Puzzle; +use std::collections::{HashSet, VecDeque}; + +#[derive(Clone, Copy, Debug)] +#[repr(u8)] +enum OpCode { + Adv = 0, + Bxl = 1, + Bst = 2, + Jnz = 3, + Bxc = 4, + Out = 5, + Bdv = 6, + Cdv = 7, +} + +impl TryFrom for OpCode { + type Error = &'static str; + + fn try_from(value: u64) -> Result { + match value { + 0 => Ok(OpCode::Adv), + 1 => Ok(OpCode::Bxl), + 2 => Ok(OpCode::Bst), + 3 => Ok(OpCode::Jnz), + 4 => Ok(OpCode::Bxc), + 5 => Ok(OpCode::Out), + 6 => Ok(OpCode::Bdv), + 7 => Ok(OpCode::Cdv), + _ => Err(""), + } + } +} + +#[derive(Clone, Copy, Debug)] +struct Instruction { + opcode: OpCode, + operand: u64, +} + +impl TryFrom<(u64, u64)> for Instruction { + type Error = &'static str; + + fn try_from(value: (u64, u64)) -> Result { + let (opcode, operand) = value; + Ok(Self { + opcode: OpCode::try_from(opcode)?, + operand, + }) + } +} + +struct Program { + a: u64, + b: u64, + c: u64, + ins: Vec, + ip: usize, +} + +impl TryFrom<&Vec> for Program { + type Error = &'static str; + + fn try_from(value: &Vec) -> Result { + let ins = (0..value.len()) + .step_by(2) + .map(|i| Instruction::try_from((value[i], value[i + 1])).unwrap()) + .collect(); + Ok(Self { + a: 0, + b: 0, + c: 0, + ins, + ip: 0, + }) + } +} + +impl Program { + fn combo(&self, operand: u64) -> u64 { + match operand { + 0..=3 => operand, + 4 => self.a, + 5 => self.b, + 6 => self.c, + _ => panic!(), + } + } + + fn op(&mut self, ins: &Instruction) -> Option { + match ins.opcode { + OpCode::Adv => { + self.a >>= self.combo(ins.operand); + self.ip += 1; + } + OpCode::Bxl => { + self.b ^= ins.operand; + self.ip += 1; + } + OpCode::Bst => { + self.b = self.combo(ins.operand) & 7; + self.ip += 1; + } + OpCode::Jnz => match self.a == 0 { + false => self.ip = ins.operand as usize, + true => self.ip += 1, + }, + OpCode::Bxc => { + self.b ^= self.c; + self.ip += 1; + } + OpCode::Out => { + let out = self.combo(ins.operand) & 7; + self.ip += 1; + return Some(out); + } + OpCode::Bdv => { + self.b = self.a >> self.combo(ins.operand); + self.ip += 1; + } + OpCode::Cdv => { + self.c = self.a >> self.combo(ins.operand); + self.ip += 1; + } + }; + None + } + + fn run(&mut self, a: u64, b: u64, c: u64) -> Vec { + self.a = a; + self.b = b; + self.c = c; + self.ip = 0; + let mut ans = vec![]; + while self.ip < self.ins.len() { + let ins = self.ins[self.ip]; + if let Some(output) = self.op(&ins) { + ans.push(output); + } + } + ans + } +} + +struct AoC2024_17; + +impl AoC2024_17 {} + +impl aoc::Puzzle for AoC2024_17 { + type Input = (u64, u64, u64, Vec); + type Output1 = String; + type Output2 = u64; + + aoc::puzzle_year_day!(2024, 17); + + fn parse_input(&self, lines: Vec) -> Self::Input { + let abc: Vec = (0..3) + .map(|i| lines[i][12..].parse::().unwrap()) + .collect(); + let ops = lines[4][9..] + .split(",") + .map(|s| s.parse::().unwrap()) + .collect(); + (abc[0], abc[1], abc[2], ops) + } + + fn part_1(&self, input: &Self::Input) -> Self::Output1 { + let (a, b, c, ops) = input; + let mut program = Program::try_from(ops).unwrap(); + program + .run(*a, *b, *c) + .into_iter() + .map(|n| n.to_string()) + .collect::>() + .join(",") + } + + fn part_2(&self, input: &Self::Input) -> Self::Output2 { + let (_, b, c, ops) = input; + let mut program = Program::try_from(ops).unwrap(); + let mut seen: HashSet = HashSet::from([0]); + let mut q: VecDeque = VecDeque::from([0]); + while !q.is_empty() { + let cand_a = q.pop_front().unwrap() * 8; + for i in 0..8 { + let na = cand_a + i; + let res = program.run(na, *b, *c); + if res == *ops { + return na; + } + if res == ops[ops.len() - res.len()..] && !seen.contains(&na) { + seen.insert(na); + q.push_back(na); + } + } + } + unreachable!(); + } + + fn samples(&self) { + aoc::puzzle_samples! { + self, part_1, TEST1, "4,6,3,5,6,3,5,2,1,0", + self, part_2, TEST2, 117440 + }; + } +} + +fn main() { + AoC2024_17 {}.run(std::env::args()); +} + +const TEST1: &str = "\ +Register A: 729 +Register B: 0 +Register C: 0 + +Program: 0,1,5,4,3,0 +"; +const TEST2: &str = "\ +Register A: 2024 +Register B: 0 +Register C: 0 + +Program: 0,3,5,4,3,0 +"; + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + pub fn samples() { + AoC2024_17 {}.samples(); + } +} diff --git a/src/main/rust/Cargo.lock b/src/main/rust/Cargo.lock index bc934bc..e0a6c59 100644 --- a/src/main/rust/Cargo.lock +++ b/src/main/rust/Cargo.lock @@ -485,6 +485,13 @@ dependencies = [ "itertools", ] +[[package]] +name = "AoC2024_17" +version = "0.1.0" +dependencies = [ + "aoc", +] + [[package]] name = "aho-corasick" version = "1.0.2"