Compare commits
2 Commits
4ce7184b1e
...
0ecea97752
Author | SHA1 | Date |
---|---|---|
![]() |
0ecea97752 | |
![]() |
dc5f488212 |
|
@ -0,0 +1,287 @@
|
||||||
|
use std::{
|
||||||
|
cmp::{Ordering, Reverse},
|
||||||
|
collections::BinaryHeap,
|
||||||
|
};
|
||||||
|
|
||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use hashbrown::HashSet;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
|
enum Cell {
|
||||||
|
Empty,
|
||||||
|
Wall,
|
||||||
|
}
|
||||||
|
|
||||||
|
type Input = ((usize, usize), (usize, usize), Vec<Vec<Cell>>);
|
||||||
|
|
||||||
|
#[aoc_generator(day16)]
|
||||||
|
fn parse(input: &str) -> Input {
|
||||||
|
let mut pos = (0, 0);
|
||||||
|
let mut end = (0, 0);
|
||||||
|
let map = input
|
||||||
|
.lines()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(y, line)| {
|
||||||
|
line.chars()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(x, c)| match c {
|
||||||
|
'#' => Cell::Wall,
|
||||||
|
'.' => Cell::Empty,
|
||||||
|
'E' => {
|
||||||
|
end = (x, y);
|
||||||
|
Cell::Empty
|
||||||
|
}
|
||||||
|
'S' => {
|
||||||
|
pos = (x, y);
|
||||||
|
Cell::Empty
|
||||||
|
}
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
(pos, end, map)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day16, part1)]
|
||||||
|
fn part1(input: &Input) -> i64 {
|
||||||
|
let start = (input.0 .0 as i64, input.0 .1 as i64);
|
||||||
|
let end = (input.1 .0 as i64, input.1 .1 as i64);
|
||||||
|
let map = input.2.clone();
|
||||||
|
let w = map[0].len();
|
||||||
|
let h = map.len();
|
||||||
|
let mut d = vec![vec![[i64::MAX; 4]; w]; h];
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
let mut queue: BinaryHeap<Reverse<(i64, i64, i64, i64, i64)>> = BinaryHeap::new();
|
||||||
|
d[start.1 as usize][start.0 as usize][1] = 0;
|
||||||
|
queue.push(Reverse((0, start.0, start.1, 1, 0)));
|
||||||
|
|
||||||
|
while let Some(Reverse((dist, pos_x, pos_y, dir_x, dir_y))) = queue.pop() {
|
||||||
|
let dir_num = match (dir_x, dir_y) {
|
||||||
|
(0, -1) => 0,
|
||||||
|
(1, 0) => 1,
|
||||||
|
(0, 1) => 2,
|
||||||
|
(-1, 0) => 3,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if d[pos_y as usize][pos_x as usize][dir_num] < dist {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos_x, pos_y) == end {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if map[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize] == Cell::Empty {
|
||||||
|
let dist_next = &mut d[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num];
|
||||||
|
if (dist + 1).cmp(dist_next) == Ordering::Less {
|
||||||
|
*dist_next = dist + 1;
|
||||||
|
queue.push(Reverse((
|
||||||
|
*dist_next,
|
||||||
|
pos_x + dir_x,
|
||||||
|
pos_y + dir_y,
|
||||||
|
dir_x,
|
||||||
|
dir_y,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 3) % 4];
|
||||||
|
if (dist + 1000).cmp(dist_next) == Ordering::Less {
|
||||||
|
*dist_next = dist + 1000;
|
||||||
|
queue.push(Reverse((*dist_next, pos_x, pos_y, dir_y, -dir_x)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 1) % 4];
|
||||||
|
if (dist + 1000).cmp(dist_next) == Ordering::Less {
|
||||||
|
*dist_next = dist + 1000;
|
||||||
|
queue.push(Reverse((*dist_next, pos_x, pos_y, -dir_y, dir_x)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*d[end.1 as usize][end.0 as usize].iter().min().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day16, part2)]
|
||||||
|
fn part2(input: &Input) -> i64 {
|
||||||
|
let start = (input.0 .0 as i64, input.0 .1 as i64);
|
||||||
|
let end = (input.1 .0 as i64, input.1 .1 as i64);
|
||||||
|
let map = input.2.clone();
|
||||||
|
let w = map[0].len();
|
||||||
|
let h = map.len();
|
||||||
|
let mut d = vec![vec![[i64::MAX; 4]; w]; h];
|
||||||
|
let mut b = vec![vec![[vec![], vec![], vec![], vec![]]; w]; h];
|
||||||
|
|
||||||
|
#[allow(clippy::type_complexity)]
|
||||||
|
let mut queue: BinaryHeap<Reverse<(i64, i64, i64, i64, i64)>> = BinaryHeap::new();
|
||||||
|
d[start.1 as usize][start.0 as usize][1] = 0;
|
||||||
|
queue.push(Reverse((0, start.0, start.1, 1, 0)));
|
||||||
|
|
||||||
|
while let Some(Reverse((dist, pos_x, pos_y, dir_x, dir_y))) = queue.pop() {
|
||||||
|
let dir_num = match (dir_x, dir_y) {
|
||||||
|
(0, -1) => 0,
|
||||||
|
(1, 0) => 1,
|
||||||
|
(0, 1) => 2,
|
||||||
|
(-1, 0) => 3,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
|
||||||
|
if d[pos_y as usize][pos_x as usize][dir_num] < dist {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pos_x, pos_y) == end {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if map[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize] == Cell::Empty {
|
||||||
|
let dist_next = &mut d[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num];
|
||||||
|
let back_next = &mut b[(pos_y + dir_y) as usize][(pos_x + dir_x) as usize][dir_num];
|
||||||
|
if (dist + 1).cmp(dist_next) == Ordering::Less {
|
||||||
|
*dist_next = dist + 1;
|
||||||
|
back_next.clear();
|
||||||
|
back_next.push((pos_x, pos_y, dir_num));
|
||||||
|
queue.push(Reverse((
|
||||||
|
*dist_next,
|
||||||
|
pos_x + dir_x,
|
||||||
|
pos_y + dir_y,
|
||||||
|
dir_x,
|
||||||
|
dir_y,
|
||||||
|
)));
|
||||||
|
} else if (dist + 1).cmp(dist_next) == Ordering::Equal {
|
||||||
|
back_next.push((pos_x, pos_y, dir_num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 3) % 4];
|
||||||
|
let back_next = &mut b[pos_y as usize][pos_x as usize][(dir_num + 3) % 4];
|
||||||
|
if (dist + 1000).cmp(dist_next) == Ordering::Less {
|
||||||
|
*dist_next = dist + 1000;
|
||||||
|
back_next.clear();
|
||||||
|
back_next.push((pos_x, pos_y, dir_num));
|
||||||
|
queue.push(Reverse((*dist_next, pos_x, pos_y, dir_y, -dir_x)));
|
||||||
|
} else if (dist + 1000).cmp(dist_next) == Ordering::Equal {
|
||||||
|
back_next.push((pos_x, pos_y, dir_num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
let dist_next = &mut d[pos_y as usize][pos_x as usize][(dir_num + 1) % 4];
|
||||||
|
let back_next = &mut b[pos_y as usize][pos_x as usize][(dir_num + 1) % 4];
|
||||||
|
if (dist + 1000).cmp(dist_next) == Ordering::Less {
|
||||||
|
*dist_next = dist + 1000;
|
||||||
|
back_next.clear();
|
||||||
|
back_next.push((pos_x, pos_y, dir_num));
|
||||||
|
queue.push(Reverse((*dist_next, pos_x, pos_y, -dir_y, dir_x)));
|
||||||
|
} else if (dist + 1000).cmp(dist_next) == Ordering::Equal {
|
||||||
|
back_next.push((pos_x, pos_y, dir_num));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut visited = HashSet::new();
|
||||||
|
let dist_min = *d[end.1 as usize][end.0 as usize].iter().min().unwrap();
|
||||||
|
let mut stack = vec![];
|
||||||
|
d[end.1 as usize][end.0 as usize]
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.for_each(|(i, d)| {
|
||||||
|
if *d == dist_min {
|
||||||
|
stack.push((end.0, end.1, i));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
while let Some((pos_x, pos_y, dir_num)) = stack.pop() {
|
||||||
|
visited.insert((pos_x, pos_y));
|
||||||
|
stack.append(&mut b[pos_y as usize][pos_x as usize][dir_num]);
|
||||||
|
}
|
||||||
|
|
||||||
|
visited.len() as i64
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(
|
||||||
|
part1(&parse(
|
||||||
|
"###############
|
||||||
|
#.......#....E#
|
||||||
|
#.#.###.#.###.#
|
||||||
|
#.....#.#...#.#
|
||||||
|
#.###.#####.#.#
|
||||||
|
#.#.#.......#.#
|
||||||
|
#.#.#####.###.#
|
||||||
|
#...........#.#
|
||||||
|
###.#.#####.#.#
|
||||||
|
#...#.....#.#.#
|
||||||
|
#.#.#.###.#.#.#
|
||||||
|
#.....#...#.#.#
|
||||||
|
#.###.#.#.#.#.#
|
||||||
|
#S..#.....#...#
|
||||||
|
###############"
|
||||||
|
)),
|
||||||
|
7036
|
||||||
|
);
|
||||||
|
// assert_eq!(
|
||||||
|
// part1(&parse(include_str!("../input/2024/day16.txt"))),
|
||||||
|
// 85420
|
||||||
|
// );
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(
|
||||||
|
part2(&parse(
|
||||||
|
"###############
|
||||||
|
#.......#....E#
|
||||||
|
#.#.###.#.###.#
|
||||||
|
#.....#.#...#.#
|
||||||
|
#.###.#####.#.#
|
||||||
|
#.#.#.......#.#
|
||||||
|
#.#.#####.###.#
|
||||||
|
#...........#.#
|
||||||
|
###.#.#####.#.#
|
||||||
|
#...#.....#.#.#
|
||||||
|
#.#.#.###.#.#.#
|
||||||
|
#.....#...#.#.#
|
||||||
|
#.###.#.#.#.#.#
|
||||||
|
#S..#.....#...#
|
||||||
|
###############"
|
||||||
|
)),
|
||||||
|
45
|
||||||
|
);
|
||||||
|
assert_eq!(
|
||||||
|
part2(&parse(
|
||||||
|
"#################
|
||||||
|
#...#...#...#..E#
|
||||||
|
#.#.#.#.#.#.#.#.#
|
||||||
|
#.#.#.#...#...#.#
|
||||||
|
#.#.#.#.###.#.#.#
|
||||||
|
#...#.#.#.....#.#
|
||||||
|
#.#.#.#.#.#####.#
|
||||||
|
#.#...#.#.#.....#
|
||||||
|
#.#.#####.#.###.#
|
||||||
|
#.#.#.......#...#
|
||||||
|
#.#.###.#####.###
|
||||||
|
#.#.#...#.....#.#
|
||||||
|
#.#.#.#####.###.#
|
||||||
|
#.#.#.........#.#
|
||||||
|
#.#.#.#########.#
|
||||||
|
#S#.............#
|
||||||
|
#################"
|
||||||
|
)),
|
||||||
|
64
|
||||||
|
);
|
||||||
|
// assert_eq!(part2(&parse(include_str!("../input/2024/day16.txt"))), 492);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
// }
|
||||||
|
}
|
|
@ -1,3 +1,6 @@
|
||||||
|
mod day19;
|
||||||
|
mod day18;
|
||||||
|
mod day17;
|
||||||
mod day1;
|
mod day1;
|
||||||
mod day10;
|
mod day10;
|
||||||
mod day11;
|
mod day11;
|
||||||
|
@ -5,6 +8,7 @@ mod day12;
|
||||||
mod day13;
|
mod day13;
|
||||||
mod day14;
|
mod day14;
|
||||||
mod day15;
|
mod day15;
|
||||||
|
mod day16;
|
||||||
mod day2;
|
mod day2;
|
||||||
mod day3;
|
mod day3;
|
||||||
mod day4;
|
mod day4;
|
||||||
|
|
Loading…
Reference in New Issue