Skip to content

Commit

Permalink
Merge pull request #118 from ephemient/rs/day17
Browse files Browse the repository at this point in the history
Day 17: Chronospatial Computer
  • Loading branch information
ephemient authored Dec 18, 2024
2 parents 4fdba00 + fe6568c commit af90d6f
Show file tree
Hide file tree
Showing 5 changed files with 133 additions and 5 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,4 @@ Development occurs in language-specific directories:
|[Day14.hs](hs/src/Day14.hs)|[Day14.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day14.kt)|[day14.py](py/aoc2024/day14.py)|[day14.rs](rs/src/day14.rs)|
|[Day15.hs](hs/src/Day15.hs)|[Day15.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day15.kt)|[day15.py](py/aoc2024/day15.py)|[day15.rs](rs/src/day15.rs)|
|[Day16.hs](hs/src/Day16.hs)|[Day16.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day16.kt)|[day16.py](py/aoc2024/day16.py)|[day16.rs](rs/src/day16.rs)|
|[Day17.hs](hs/src/Day17.hs)|[Day17.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day17.kt)|[day17.py](py/aoc2024/day17.py)||
|[Day17.hs](hs/src/Day17.hs)|[Day17.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day17.kt)|[day17.py](py/aoc2024/day17.py)|[day17.rs](rs/src/day17.rs)|
10 changes: 8 additions & 2 deletions rs/benches/criterion.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use aoc2024::{
day1, day10, day11, day12, day13, day14, day15, day16, day2, day3, day4, day5, day6, day7,
day8, day9,
day1, day10, day11, day12, day13, day14, day15, day16, day17, day2, day3, day4, day5, day6,
day7, day8, day9,
};
use criterion::{black_box, Criterion};
use std::env;
Expand Down Expand Up @@ -113,6 +113,12 @@ fn aoc2024_bench(c: &mut Criterion) -> io::Result<()> {
g.bench_function("part 2", |b| b.iter(|| day16::part2(black_box(&data))));
g.finish();

let data = get_day_input(17)?;
let mut g = c.benchmark_group("day 17");
g.bench_function("part 1", |b| b.iter(|| day17::part1(black_box(&data))));
g.bench_function("part 2", |b| b.iter(|| day17::part2(black_box(&data))));
g.finish();

Ok(())
}

Expand Down
113 changes: 113 additions & 0 deletions rs/src/day17.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
use itertools::Itertools;

fn parse(data: &str) -> Option<(usize, usize, usize, Vec<usize>)> {
let mut iter = data.lines();
let a = iter.next()?.strip_prefix("Register A: ")?.parse().ok()?;
let b = iter.next()?.strip_prefix("Register B: ")?.parse().ok()?;
let c = iter.next()?.strip_prefix("Register C: ")?.parse().ok()?;
let program = iter
.find(|line| !line.is_empty())?
.strip_prefix("Program: ")?
.split(',')
.map(|s| s.parse())
.collect::<Result<_, _>>()
.ok()?;
Some((a, b, c, program))
}

fn run(mut a: usize, mut b: usize, mut c: usize, program: &[usize]) -> Option<Vec<usize>> {
let mut outputs = vec![];
let mut ip = 0;
while let Some((instruction, operand)) = program.get(ip).zip(program.get(ip + 1)) {
let combo = match operand {
0..=3 => *operand,
4 => a,
5 => b,
6 => c,
_ => return None,
};
match instruction {
0 => a >>= combo,
1 => b ^= operand,
2 => b = combo & 7,
3 => {
if a != 0 {
ip = *operand;
continue;
}
}
4 => b ^= c,
5 => outputs.push(combo & 7),
6 => b = a >> combo,
7 => c = a >> combo,
_ => return None,
}
ip += 2;
}
Some(outputs)
}

pub fn part1(data: &str) -> Option<String> {
let (a, b, c, program) = parse(data)?;
Some(
run(a, b, c, &program)?
.into_iter()
.map(|num| num.to_string())
.join(","),
)
}

pub fn part2(data: &str) -> Option<usize> {
let (_, b, c, program) = parse(data)?;
let mut candidates = vec![0];
while !candidates.is_empty() {
let mut next = vec![];
for base in candidates {
for i in 0..=7 {
let a = 8 * base + i;
let output = run(a, b, c, &program)?;
if output == program {
return Some(a);
}
if program.ends_with(&output) {
next.push(a);
}
}
}
candidates = next;
}
None
}

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

static EXAMPLE_1: &str = indoc! {"
Register A: 729
Register B: 0
Register C: 0
Program: 0,1,5,4,3,0
"};

static EXAMPLE_2: &str = indoc! {"
Register A: 2024
Register B: 0
Register C: 0
Program: 0,3,5,4,3,0
"};

#[test]
fn part1_examples() {
assert_eq!(Some("4,6,3,5,6,3,5,2,1,0".to_string()), part1(EXAMPLE_1));
}

#[test]
fn part2_examples() {
assert_eq!(Some(117440), part2(EXAMPLE_2));
}
}
1 change: 1 addition & 0 deletions rs/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,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
12 changes: 10 additions & 2 deletions rs/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use anyhow::anyhow;
use aoc2024::{
day1, day10, day11, day12, day13, day14, day15, day16, day2, day3, day4, day5, day6, day7,
day8, day9,
day1, day10, day11, day12, day13, day14, day15, day16, day17, day2, day3, day4, day5, day6,
day7, day8, day9,
};
use std::collections::HashSet;
use std::env;
Expand Down Expand Up @@ -148,5 +148,13 @@ fn main() -> anyhow::Result<()> {
println!();
}

if args.is_empty() || args.contains("17") {
println!("Day 17");
let data = get_day_input(17)?;
println!("{}", day17::part1(&data).ok_or(anyhow!("None"))?);
println!("{:?}", day17::part2(&data).ok_or(anyhow!("None"))?);
println!();
}

Ok(())
}

0 comments on commit af90d6f

Please sign in to comment.