Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 3b10e15

Browse filesBrowse files
committed
Updated lib and added day 17 Rust based solution
1 parent bd50d62 commit 3b10e15
Copy full SHA for 3b10e15

File tree

Expand file treeCollapse file tree

5 files changed

+276
-17
lines changed
Filter options
Expand file treeCollapse file tree

5 files changed

+276
-17
lines changed

‎2024/day17/Cargo.toml

Copy file name to clipboard
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "day17"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[dependencies]
7+
utils = { workspace = true }
8+
9+
[[bin]]
10+
name = "day17"
11+
path = "day17.rs"

‎2024/day17/day17.rs

Copy file name to clipboard
+202Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
use utils;
2+
3+
struct Computer {
4+
a_reg: usize,
5+
b_reg: usize,
6+
c_reg: usize,
7+
instruction_pointer: usize,
8+
program: Vec<usize>,
9+
output_buffer: Vec<usize>,
10+
}
11+
12+
impl Computer {
13+
fn new(a_reg: usize, b_reg: usize, c_reg: usize, program: Vec<usize>) -> Computer {
14+
Computer {
15+
a_reg,
16+
b_reg,
17+
c_reg,
18+
instruction_pointer: 0,
19+
program,
20+
output_buffer: vec![],
21+
}
22+
}
23+
24+
fn run(&mut self) {
25+
while self.instruction_pointer < self.program.len() {
26+
self.execute_instruction();
27+
}
28+
}
29+
30+
fn execute_instruction(&mut self) {
31+
let operand = self.program[self.instruction_pointer + 1];
32+
match self.program[self.instruction_pointer] {
33+
0 => self.adv(operand),
34+
1 => self.bxl(operand),
35+
2 => self.bst(operand),
36+
3 => self.jnz(operand),
37+
4 => self.bxc(),
38+
5 => self.out(operand),
39+
6 => self.bdv(operand),
40+
7 => self.cdv(operand),
41+
_ => unreachable!(),
42+
}
43+
}
44+
45+
fn process_output(&self) -> String {
46+
self.output_buffer
47+
.iter()
48+
.map(|o| o.to_string())
49+
.collect::<Vec<String>>()
50+
.join(",")
51+
}
52+
53+
fn combo_operand(&mut self, operand: usize) -> usize {
54+
match operand {
55+
0..=3 => operand as usize,
56+
4 => self.a_reg,
57+
5 => self.b_reg,
58+
6 => self.c_reg,
59+
_ => panic!("Invalid operand {}", operand),
60+
}
61+
}
62+
63+
fn adv(&mut self, operand: usize) {
64+
let operand = self.combo_operand(operand);
65+
self.a_reg >>= operand;
66+
self.instruction_pointer += 2;
67+
}
68+
69+
fn bxl(&mut self, operand: usize) {
70+
self.b_reg ^= operand;
71+
self.instruction_pointer += 2;
72+
}
73+
74+
fn bst(&mut self, operand: usize) {
75+
let operand = self.combo_operand(operand);
76+
self.b_reg = operand & 7;
77+
self.instruction_pointer += 2;
78+
}
79+
80+
fn jnz(&mut self, operand: usize) {
81+
if self.a_reg != 0 {
82+
self.instruction_pointer = operand.try_into().unwrap();
83+
} else {
84+
self.instruction_pointer += 2;
85+
}
86+
}
87+
88+
fn bxc(&mut self) {
89+
self.b_reg ^= self.c_reg;
90+
self.instruction_pointer += 2;
91+
}
92+
93+
fn out(&mut self, operand: usize) {
94+
let operand = self.combo_operand(operand);
95+
self.output_buffer.push(operand & 7);
96+
self.instruction_pointer += 2;
97+
}
98+
99+
fn bdv(&mut self, operand: usize) {
100+
let operand = self.combo_operand(operand);
101+
self.b_reg = self.a_reg >> operand;
102+
self.instruction_pointer += 2;
103+
}
104+
105+
fn cdv(&mut self, operand: usize) {
106+
let operand = self.combo_operand(operand);
107+
self.c_reg = self.a_reg >> operand;
108+
self.instruction_pointer += 2;
109+
}
110+
}
111+
112+
fn get_registers_and_program(input: String) -> (usize, usize, usize, Vec<usize>) {
113+
let (registers, program) = input.split_once("\n\n").unwrap();
114+
115+
let instructions = program
116+
.strip_prefix("Program: ")
117+
.unwrap()
118+
.split(",")
119+
.map(|c| c.trim().parse::<usize>().unwrap())
120+
.collect::<Vec<_>>();
121+
122+
let [a, b, c]: [usize; 3] = registers
123+
.lines()
124+
.map(|l| l.split_once(": ").unwrap().1.parse::<usize>().unwrap())
125+
.collect::<Vec<_>>()
126+
.try_into()
127+
.unwrap();
128+
129+
(a, b, c, instructions)
130+
}
131+
132+
fn part1(input_program: String) -> String {
133+
let (a_register, b_register, c_register, program) = get_registers_and_program(input_program);
134+
135+
let mut computer = Computer::new(a_register, b_register, c_register, program);
136+
computer.run();
137+
138+
computer.process_output()
139+
}
140+
141+
fn part2(input_program: String) -> usize {
142+
let (_, b_register, c_register, program) = get_registers_and_program(input_program);
143+
144+
let mut a_register = 0;
145+
let mut counter = 1;
146+
let mut start_i = 0;
147+
148+
while counter <= program.len() as i32 && counter >= 0 {
149+
a_register <<= 3;
150+
151+
let mut found = false;
152+
for i in start_i..8 {
153+
let mut computer =
154+
Computer::new(a_register + i, b_register, c_register, program.clone());
155+
computer.run();
156+
157+
if program[program.len().saturating_sub(counter as usize)..] == computer.output_buffer {
158+
found = true;
159+
a_register += i;
160+
start_i = 0;
161+
counter += 1;
162+
break;
163+
}
164+
}
165+
166+
if !found {
167+
counter -= 1;
168+
a_register >>= 3;
169+
start_i = (a_register % 8) + 1;
170+
a_register >>= 3;
171+
}
172+
}
173+
174+
a_register
175+
}
176+
177+
#[cfg(test)]
178+
mod test {
179+
use super::*;
180+
181+
#[test]
182+
fn test1() {
183+
assert_eq!(
184+
part1(utils::read_file("./sample1.txt")),
185+
"4,6,3,5,6,3,5,2,1,0"
186+
)
187+
}
188+
189+
#[test]
190+
fn test2() {
191+
assert_eq!(part2(utils::read_file("./sample2.txt")), 117440)
192+
}
193+
}
194+
195+
fn main() {
196+
utils::run(
197+
17,
198+
vec!["sample1.txt", "sample2.txt", "input.txt"],
199+
&part1,
200+
&part2,
201+
);
202+
}

‎2024/day17/sample1.txt

Copy file name to clipboard
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 729
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 0,1,5,4,3,0

‎2024/day17/sample2.txt

Copy file name to clipboard
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 2024
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 0,3,5,4,3,0

‎2024/libs/utils/src/lib.rs

Copy file name to clipboardExpand all lines: 2024/libs/utils/src/lib.rs
+53-17Lines changed: 53 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2,14 +2,19 @@ use std::{fs, time::Instant};
22

33
pub mod coordinates;
44

5-
pub fn run<T>(day: i32, input_files: Vec<&str>, part1: &dyn Fn(String) -> T, part2: &dyn Fn(String) -> T)
6-
where
7-
T: Into<i64> + std::fmt::Display,
5+
pub fn run<T1, T2>(
6+
day: i32,
7+
input_files: Vec<&str>,
8+
part1: &dyn Fn(String) -> T1,
9+
part2: &dyn Fn(String) -> T2,
10+
) where
11+
T1: std::fmt::Display,
12+
T2: std::fmt::Display,
813
{
914
for input_file in input_files {
1015
let mut output: Vec<String> = vec![];
1116

12-
if !fs::exists(input_file).unwrap() {
17+
if !fs::metadata(input_file).is_ok() {
1318
println!("Skipping {} as the file doesn't exist on the file system", input_file);
1419
continue;
1520
}
@@ -18,30 +23,61 @@ where
1823

1924
println!("Running {}...", input_file);
2025

21-
output.push(format!("+---------+-------------+------------+"));
22-
output.push(format!("| Day {:>2} | Result | Time Taken |", day));
23-
output.push(format!("+---------+-------------+------------+"));
24-
26+
// Collect results
2527
let start_part1 = Instant::now();
2628
let part1_result = part1(input.clone());
2729
let duration_part1 = start_part1.elapsed().as_nanos();
28-
output.push(format!(
29-
"| Part 1 | {:<11} | {:>10} |",
30-
part1_result,
31-
format_duration(duration_part1)
32-
));
3330

3431
let start_part2 = Instant::now();
3532
let part2_result = part2(input.clone());
3633
let duration_part2 = start_part2.elapsed().as_nanos();
34+
35+
// Determine column widths dynamically
36+
let day_column = format!("Day {}", day);
37+
let part1_result_str = part1_result.to_string();
38+
let part2_result_str = part2_result.to_string();
39+
let time1 = format_duration(duration_part1);
40+
let time2 = format_duration(duration_part2);
41+
42+
let day_width = day_column.len().max("Part 2".len());
43+
let result_width = "Result".len()
44+
.max(part1_result_str.len())
45+
.max(part2_result_str.len());
46+
let time_width = "Time Taken".len().max(time1.len()).max(time2.len());
47+
48+
// Draw table header
49+
output.push(format!(
50+
"+-{:-<day_width$}-+-{:-<result_width$}-+-{:-<time_width$}-+",
51+
"", "", ""
52+
));
53+
output.push(format!(
54+
"| {:^day_width$} | {:^result_width$} | {:^time_width$} |",
55+
day_column, "Result", "Time Taken"
56+
));
3757
output.push(format!(
38-
"| Part 2 | {:<11} | {:>10} |",
39-
part2_result,
40-
format_duration(duration_part2)
58+
"+-{:-<day_width$}-+-{:-<result_width$}-+-{:-<time_width$}-+",
59+
"", "", ""
4160
));
4261

43-
output.push(format!("+---------+-------------+------------+"));
62+
// Part 1 row
63+
output.push(format!(
64+
"| {:<day_width$} | {:<result_width$} | {:>time_width$} |",
65+
"Part 1", part1_result_str, time1
66+
));
67+
68+
// Part 2 row
69+
output.push(format!(
70+
"| {:<day_width$} | {:<result_width$} | {:>time_width$} |",
71+
"Part 2", part2_result_str, time2
72+
));
73+
74+
// Draw table footer
75+
output.push(format!(
76+
"+-{:-<day_width$}-+-{:-<result_width$}-+-{:-<time_width$}-+",
77+
"", "", ""
78+
));
4479

80+
// Print table
4581
println!("{}", output.join("\n"));
4682
println!("");
4783
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.