From 0ecea977521602d7206fc3d64db5fa1a2a40b66b Mon Sep 17 00:00:00 2001 From: Jan-Bulthuis Date: Fri, 20 Dec 2024 01:41:41 +0100 Subject: [PATCH] day17-19 --- aoc_2024/src/day16.rs | 10 +-- aoc_2024/src/day17.rs | 126 ++++++++++++++++++++++++++ aoc_2024/src/day18.rs | 205 ++++++++++++++++++++++++++++++++++++++++++ aoc_2024/src/day19.rs | 120 +++++++++++++++++++++++++ aoc_2024/src/lib.rs | 3 + 5 files changed, 459 insertions(+), 5 deletions(-) create mode 100644 aoc_2024/src/day17.rs create mode 100644 aoc_2024/src/day18.rs create mode 100644 aoc_2024/src/day19.rs diff --git a/aoc_2024/src/day16.rs b/aoc_2024/src/day16.rs index 5bf475a..1945bb4 100644 --- a/aoc_2024/src/day16.rs +++ b/aoc_2024/src/day16.rs @@ -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); } } diff --git a/aoc_2024/src/day17.rs b/aoc_2024/src/day17.rs new file mode 100644 index 0000000..5640040 --- /dev/null +++ b/aoc_2024/src/day17.rs @@ -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); + +#[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::>() + .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" + ); + } +} diff --git a/aoc_2024/src/day18.rs b/aoc_2024/src/day18.rs new file mode 100644 index 0000000..abe4278 --- /dev/null +++ b/aoc_2024/src/day18.rs @@ -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" + ); + } +} diff --git a/aoc_2024/src/day19.rs b/aoc_2024/src/day19.rs new file mode 100644 index 0000000..fed4e74 --- /dev/null +++ b/aoc_2024/src/day19.rs @@ -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>); + +#[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("")), 0); + // } +} diff --git a/aoc_2024/src/lib.rs b/aoc_2024/src/lib.rs index c53a429..b682b8c 100644 --- a/aoc_2024/src/lib.rs +++ b/aoc_2024/src/lib.rs @@ -1,3 +1,6 @@ +mod day19; +mod day18; +mod day17; mod day1; mod day10; mod day11;