Skip to content

Commit 96c6cb8

Browse files
committed
AoC 2024 Day 17 - rust
1 parent 69bd9e3 commit 96c6cb8

File tree

4 files changed

+252
-1
lines changed

4 files changed

+252
-1
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
| ---| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
1111
| 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) | | | | | | | | |
1212
| 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) | | | | | | | | | | |
13-
| 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) | | | | | | | | | |
13+
| 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) | | | | | | | | |
1414
<!-- @END:ImplementationsTable:2024@ -->
1515

1616
## 2023

src/main/rust/AoC2024_17/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
[package]
2+
name = "AoC2024_17"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
aoc = { path = "../aoc" }

src/main/rust/AoC2024_17/src/main.rs

Lines changed: 237 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,237 @@
1+
// #![allow(non_snake_case)]
2+
3+
use aoc::Puzzle;
4+
use std::collections::{HashSet, VecDeque};
5+
6+
#[derive(Clone, Copy, Debug)]
7+
#[repr(u8)]
8+
enum OpCode {
9+
Adv = 0,
10+
Bxl = 1,
11+
Bst = 2,
12+
Jnz = 3,
13+
Bxc = 4,
14+
Out = 5,
15+
Bdv = 6,
16+
Cdv = 7,
17+
}
18+
19+
impl TryFrom<u64> for OpCode {
20+
type Error = &'static str;
21+
22+
fn try_from(value: u64) -> Result<Self, Self::Error> {
23+
match value {
24+
0 => Ok(OpCode::Adv),
25+
1 => Ok(OpCode::Bxl),
26+
2 => Ok(OpCode::Bst),
27+
3 => Ok(OpCode::Jnz),
28+
4 => Ok(OpCode::Bxc),
29+
5 => Ok(OpCode::Out),
30+
6 => Ok(OpCode::Bdv),
31+
7 => Ok(OpCode::Cdv),
32+
_ => Err(""),
33+
}
34+
}
35+
}
36+
37+
#[derive(Clone, Copy, Debug)]
38+
struct Instruction {
39+
opcode: OpCode,
40+
operand: u64,
41+
}
42+
43+
impl TryFrom<(u64, u64)> for Instruction {
44+
type Error = &'static str;
45+
46+
fn try_from(value: (u64, u64)) -> Result<Self, Self::Error> {
47+
let (opcode, operand) = value;
48+
Ok(Self {
49+
opcode: OpCode::try_from(opcode)?,
50+
operand,
51+
})
52+
}
53+
}
54+
55+
struct Program {
56+
a: u64,
57+
b: u64,
58+
c: u64,
59+
ins: Vec<Instruction>,
60+
ip: usize,
61+
}
62+
63+
impl TryFrom<&Vec<u64>> for Program {
64+
type Error = &'static str;
65+
66+
fn try_from(value: &Vec<u64>) -> Result<Self, Self::Error> {
67+
let ins = (0..value.len())
68+
.step_by(2)
69+
.map(|i| Instruction::try_from((value[i], value[i + 1])).unwrap())
70+
.collect();
71+
Ok(Self {
72+
a: 0,
73+
b: 0,
74+
c: 0,
75+
ins,
76+
ip: 0,
77+
})
78+
}
79+
}
80+
81+
impl Program {
82+
fn combo(&self, operand: u64) -> u64 {
83+
match operand {
84+
0..=3 => operand,
85+
4 => self.a,
86+
5 => self.b,
87+
6 => self.c,
88+
_ => panic!(),
89+
}
90+
}
91+
92+
fn op(&mut self, ins: &Instruction) -> Option<u64> {
93+
match ins.opcode {
94+
OpCode::Adv => {
95+
self.a >>= self.combo(ins.operand);
96+
self.ip += 1;
97+
}
98+
OpCode::Bxl => {
99+
self.b ^= ins.operand;
100+
self.ip += 1;
101+
}
102+
OpCode::Bst => {
103+
self.b = self.combo(ins.operand) & 7;
104+
self.ip += 1;
105+
}
106+
OpCode::Jnz => match self.a == 0 {
107+
false => self.ip = ins.operand as usize,
108+
true => self.ip += 1,
109+
},
110+
OpCode::Bxc => {
111+
self.b ^= self.c;
112+
self.ip += 1;
113+
}
114+
OpCode::Out => {
115+
let out = self.combo(ins.operand) & 7;
116+
self.ip += 1;
117+
return Some(out);
118+
}
119+
OpCode::Bdv => {
120+
self.b = self.a >> self.combo(ins.operand);
121+
self.ip += 1;
122+
}
123+
OpCode::Cdv => {
124+
self.c = self.a >> self.combo(ins.operand);
125+
self.ip += 1;
126+
}
127+
};
128+
None
129+
}
130+
131+
fn run(&mut self, a: u64, b: u64, c: u64) -> Vec<u64> {
132+
self.a = a;
133+
self.b = b;
134+
self.c = c;
135+
self.ip = 0;
136+
let mut ans = vec![];
137+
while self.ip < self.ins.len() {
138+
let ins = self.ins[self.ip];
139+
if let Some(output) = self.op(&ins) {
140+
ans.push(output);
141+
}
142+
}
143+
ans
144+
}
145+
}
146+
147+
struct AoC2024_17;
148+
149+
impl AoC2024_17 {}
150+
151+
impl aoc::Puzzle for AoC2024_17 {
152+
type Input = (u64, u64, u64, Vec<u64>);
153+
type Output1 = String;
154+
type Output2 = u64;
155+
156+
aoc::puzzle_year_day!(2024, 17);
157+
158+
fn parse_input(&self, lines: Vec<String>) -> Self::Input {
159+
let abc: Vec<u64> = (0..3)
160+
.map(|i| lines[i][12..].parse::<u64>().unwrap())
161+
.collect();
162+
let ops = lines[4][9..]
163+
.split(",")
164+
.map(|s| s.parse::<u64>().unwrap())
165+
.collect();
166+
(abc[0], abc[1], abc[2], ops)
167+
}
168+
169+
fn part_1(&self, input: &Self::Input) -> Self::Output1 {
170+
let (a, b, c, ops) = input;
171+
let mut program = Program::try_from(ops).unwrap();
172+
program
173+
.run(*a, *b, *c)
174+
.into_iter()
175+
.map(|n| n.to_string())
176+
.collect::<Vec<String>>()
177+
.join(",")
178+
}
179+
180+
fn part_2(&self, input: &Self::Input) -> Self::Output2 {
181+
let (_, b, c, ops) = input;
182+
let mut program = Program::try_from(ops).unwrap();
183+
let mut seen: HashSet<u64> = HashSet::from([0]);
184+
let mut q: VecDeque<u64> = VecDeque::from([0]);
185+
while !q.is_empty() {
186+
let cand_a = q.pop_front().unwrap() * 8;
187+
for i in 0..8 {
188+
let na = cand_a + i;
189+
let res = program.run(na, *b, *c);
190+
if res == *ops {
191+
return na;
192+
}
193+
if res == ops[ops.len() - res.len()..] && !seen.contains(&na) {
194+
seen.insert(na);
195+
q.push_back(na);
196+
}
197+
}
198+
}
199+
unreachable!();
200+
}
201+
202+
fn samples(&self) {
203+
aoc::puzzle_samples! {
204+
self, part_1, TEST1, "4,6,3,5,6,3,5,2,1,0",
205+
self, part_2, TEST2, 117440
206+
};
207+
}
208+
}
209+
210+
fn main() {
211+
AoC2024_17 {}.run(std::env::args());
212+
}
213+
214+
const TEST1: &str = "\
215+
Register A: 729
216+
Register B: 0
217+
Register C: 0
218+
219+
Program: 0,1,5,4,3,0
220+
";
221+
const TEST2: &str = "\
222+
Register A: 2024
223+
Register B: 0
224+
Register C: 0
225+
226+
Program: 0,3,5,4,3,0
227+
";
228+
229+
#[cfg(test)]
230+
mod tests {
231+
use super::*;
232+
233+
#[test]
234+
pub fn samples() {
235+
AoC2024_17 {}.samples();
236+
}
237+
}

src/main/rust/Cargo.lock

Lines changed: 7 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)