This commit is contained in:
Jan-Bulthuis 2024-12-20 01:41:41 +01:00
parent dc5f488212
commit 0ecea97752
5 changed files with 459 additions and 5 deletions

View File

@ -232,10 +232,10 @@ mod tests {
)),
7036
);
assert_eq!(
part1(&parse(include_str!("../input/2024/day16.txt"))),
85420
);
// assert_eq!(
// part1(&parse(include_str!("../input/2024/day16.txt"))),
// 85420
// );
}
#[test]
@ -282,6 +282,6 @@ mod tests {
)),
64
);
assert_eq!(part2(&parse(include_str!("../input/2024/day16.txt"))), 492);
// assert_eq!(part2(&parse(include_str!("../input/2024/day16.txt"))), 492);
}
}

126
aoc_2024/src/day17.rs Normal file
View File

@ -0,0 +1,126 @@
use aoc_runner_derive::{aoc, aoc_generator};
use nom::bytes::complete::tag;
use nom::character::complete::i64 as parse_i64;
use nom::error::Error;
use nom::multi::separated_list1;
use nom::sequence::{preceded, separated_pair, tuple};
type Input = ((i64, i64, i64), Vec<i64>);
#[aoc_generator(day17)]
fn parse(input: &str) -> Input {
separated_pair(
tuple((
preceded(tag("Register A: "), parse_i64::<&str, Error<&str>>),
preceded(tag("\nRegister B: "), parse_i64),
preceded(tag("\nRegister C: "), parse_i64),
)),
tag("\n\n"),
preceded(tag("Program: "), separated_list1(tag(","), parse_i64)),
)(input)
.unwrap()
.1
}
#[aoc(day17, part1)]
fn part1(input: &Input) -> String {
let mut registers = input.0;
let program = input.1.clone();
let mut pc = 0;
let mut output = Vec::new();
loop {
if pc >= program.len() {
break;
}
let instruction = program[pc];
let literal_value = program[pc + 1];
let combo_value = match program[pc + 1] {
0 => 0,
1 => 1,
2 => 2,
3 => 3,
4 => registers.0,
5 => registers.1,
6 => registers.2,
_ => unreachable!(),
};
match instruction {
0 => registers.0 >>= combo_value,
1 => registers.1 ^= literal_value,
2 => registers.1 = combo_value % 8,
3 => {
if registers.0 != 0 {
pc = literal_value as usize;
continue;
}
}
4 => registers.1 ^= registers.2,
5 => output.push(combo_value % 8),
6 => registers.1 = registers.0 >> combo_value,
7 => registers.2 = registers.0 >> combo_value,
_ => unreachable!(),
}
pc += 2;
}
output
.iter()
.map(|x| x.to_string())
.collect::<Vec<String>>()
.join(",")
}
#[aoc(day17, part2)]
fn part2(input: &Input) -> i64 {
let program = input.1.clone();
let mut candidates = vec![0];
for target in program.iter().rev() {
let mut new_candidates = vec![];
for candidate in candidates {
let a = candidate;
new_candidates.extend(
(0..8)
.filter(|b| {
let a = (a << 3) + b;
let b = a % 8;
let b = b ^ 5;
let c = a >> b;
let b = b ^ c;
let b = b ^ 6;
b % 8 == *target
})
.map(|b| (a << 3) + b),
);
}
candidates = new_candidates;
}
candidates[0]
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn part1_example() {
assert_eq!(
part1(&parse(
"Register A: 729
Register B: 0
Register C: 0
Program: 0,1,5,4,3,0"
)),
"4,6,3,5,6,3,5,2,1,0"
);
}
}

205
aoc_2024/src/day18.rs Normal file
View File

@ -0,0 +1,205 @@
use std::collections::VecDeque;
use aoc_runner_derive::{aoc, aoc_generator};
use nom::{
bytes::complete::tag,
character::complete::{i64 as parse_i64, newline},
error::Error,
multi::separated_list0,
sequence::separated_pair,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Cell {
Empty,
Byte,
Visited,
}
type Input = Vec<(i64, i64)>;
#[aoc_generator(day18)]
fn parse(input: &str) -> Input {
separated_list0(
newline::<&str, Error<&str>>,
separated_pair(parse_i64, tag(","), parse_i64),
)(input)
.unwrap()
.1
}
#[aoc(day18, part1)]
fn part1(input: &Input) -> usize {
#[cfg(not(test))]
let (w, h, bytes) = (71, 71, &input[..1024]);
#[cfg(test)]
let (w, h, bytes) = (7, 7, &input[..12]);
let mut map = vec![vec![Cell::Empty; w]; h];
bytes
.iter()
.for_each(|(x, y)| map[*y as usize][*x as usize] = Cell::Byte);
let mut deque = VecDeque::new();
deque.push_back((0, 0, 0));
while let Some((x, y, depth)) = deque.pop_front() {
if x == w - 1 && y == h - 1 {
return depth;
}
if map[y][x] == Cell::Visited {
continue;
}
map[y][x] = Cell::Visited;
if x >= 1 && map[y][x - 1] == Cell::Empty {
deque.push_back((x - 1, y, depth + 1));
}
if x < w - 1 && map[y][x + 1] == Cell::Empty {
deque.push_back((x + 1, y, depth + 1));
}
if y >= 1 && map[y - 1][x] == Cell::Empty {
deque.push_back((x, y - 1, depth + 1));
}
if y < h - 1 && map[y + 1][x] == Cell::Empty {
deque.push_back((x, y + 1, depth + 1));
}
}
unreachable!()
}
#[aoc(day18, part2)]
fn part2(input: &Input) -> String {
#[cfg(not(test))]
let (w, h, min_idx) = (71, 71, 1024);
#[cfg(test)]
let (w, h, min_idx) = (7, 7, 12);
let (mut l, mut r) = (min_idx - 1, input.len() - 1);
while r - l > 1 {
let mut possible = false;
let mut map = vec![vec![Cell::Empty; w]; h];
let bytes = (l + r) >> 1;
input[0..bytes]
.iter()
.for_each(|(x, y)| map[*y as usize][*x as usize] = Cell::Byte);
let mut deque = VecDeque::new();
deque.push_back((0, 0, 0));
while let Some((x, y, depth)) = deque.pop_front() {
if x == w - 1 && y == h - 1 {
possible = true;
break;
}
if map[y][x] == Cell::Visited {
continue;
}
map[y][x] = Cell::Visited;
if x >= 1 && map[y][x - 1] == Cell::Empty {
deque.push_back((x - 1, y, depth + 1));
}
if x < w - 1 && map[y][x + 1] == Cell::Empty {
deque.push_back((x + 1, y, depth + 1));
}
if y >= 1 && map[y - 1][x] == Cell::Empty {
deque.push_back((x, y - 1, depth + 1));
}
if y < h - 1 && map[y + 1][x] == Cell::Empty {
deque.push_back((x, y + 1, depth + 1));
}
}
if possible {
l = bytes;
} else {
r = bytes;
}
}
format!("{},{}", input[l].0, input[l].1).to_string()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn part1_example() {
assert_eq!(
part1(&parse(
"5,4
4,2
4,5
3,0
2,1
6,3
2,4
1,5
0,6
3,3
2,6
5,1
1,2
5,5
2,5
6,5
1,4
0,4
6,4
1,1
6,1
1,0
0,5
1,6
2,0"
)),
22
);
}
#[test]
fn part2_example() {
assert_eq!(
part2(&parse(
"5,4
4,2
4,5
3,0
2,1
6,3
2,4
1,5
0,6
3,3
2,6
5,1
1,2
5,5
2,5
6,5
1,4
0,4
6,4
1,1
6,1
1,0
0,5
1,6
2,0"
)),
"6,1"
);
}
}

120
aoc_2024/src/day19.rs Normal file
View File

@ -0,0 +1,120 @@
use aoc_runner_derive::{aoc, aoc_generator};
use nom::{
bytes::complete::tag,
character::complete::{newline, one_of},
combinator::map,
multi::{many1, separated_list1},
sequence::separated_pair,
IResult,
};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Color {
White,
Blue,
Black,
Red,
Green,
}
type Input = (Vec<Vec<Color>>, Vec<Vec<Color>>);
#[aoc_generator(day19)]
fn parse(input: &str) -> Input {
separated_pair(
separated_list1(tag(", "), many1(parse_color)),
tag("\n\n"),
separated_list1(newline, many1(parse_color)),
)(input)
.unwrap()
.1
}
fn parse_color(input: &str) -> IResult<&str, Color> {
map(one_of("wubrg"), |c| match c {
'w' => Color::White,
'u' => Color::Blue,
'b' => Color::Black,
'r' => Color::Red,
'g' => Color::Green,
_ => unreachable!(),
})(input)
}
#[aoc(day19, part1)]
fn part1(input: &Input) -> usize {
let towels = &input.0;
let patterns = &input.1;
patterns
.iter()
.map(|pattern| {
let mut m = vec![0u64; pattern.len() + 1];
m[0] = 1;
for i in 1..=pattern.len() {
for towel in towels {
if towel.len() <= i && &pattern[i - towel.len()..i] == towel {
m[i] += m[i - towel.len()];
}
}
}
m[pattern.len()]
})
.filter(|n| *n > 0)
.count()
}
#[aoc(day19, part2)]
fn part2(input: &Input) -> u64 {
let towels = &input.0;
let patterns = &input.1;
patterns
.iter()
.map(|pattern| {
let mut m = vec![0u64; pattern.len() + 1];
m[0] = 1;
for i in 1..=pattern.len() {
for towel in towels {
if towel.len() <= i && &pattern[i - towel.len()..i] == towel {
m[i] += m[i - towel.len()];
}
}
}
m[pattern.len()]
})
.sum()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn part1_example() {
assert_eq!(
part1(&parse(
"r, wr, b, g, bwu, rb, gb, br
brwrr
bggr
gbbr
rrbgbr
ubwu
bwurrg
brgr
bbrgwb"
)),
6
);
}
// #[test]
// fn part2_example() {
// assert_eq!(part2(&parse("<EXAMPLE>")), 0);
// }
}

View File

@ -1,3 +1,6 @@
mod day19;
mod day18;
mod day17;
mod day1;
mod day10;
mod day11;