This commit is contained in:
Moritz Hölting 2023-12-21 13:05:51 +01:00
parent 082eb03bc1
commit 0278599411
6 changed files with 572 additions and 3 deletions

4
.gitignore vendored
View File

@ -1,2 +1,4 @@
/target
/erl_crash.dump
/erl_crash.dump
zig-out/
zig-cache/

12
Cargo.lock generated
View File

@ -206,6 +206,14 @@ dependencies = [
"num",
]
[[package]]
name = "day-21"
version = "0.0.0"
dependencies = [
"indoc",
"itertools",
]
[[package]]
name = "deprecate-until"
version = "0.1.1"
@ -448,9 +456,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3"
[[package]]
name = "pathfinding"
version = "4.4.0"
version = "4.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "752866d4511516a35883728309499db42696f388263586b70659a5461e641db5"
checksum = "3ea07a6e677e47d6a84724d4fdf88b1e37fcb49ac94e236d7caeefd8fee75c8a"
dependencies = [
"deprecate-until",
"fixedbitset",

10
day-21/Cargo.toml Normal file
View File

@ -0,0 +1,10 @@
[package]
name = "day-21"
version = "0.0.0"
edition = "2021"
[dev-dependencies]
indoc.workspace = true
[dependencies]
itertools.workspace = true

131
day-21/src/bin/input.txt Normal file
View File

@ -0,0 +1,131 @@
...................................................................................................................................
....#.............#...............#.......#..........#..................##..........#.....#..................##...#...#..........#.
...............#......#........#.......#........#.........................#.....#........#........#...#....#....#.........#....##..
..#........#........#.##........#....#...#.....................................#................#.#...#..#....................#....
...................#.............#........#.....#........#.........................#.......#...#.........#...........#...........#.
...##.#....#...#.#..#....#.......##..#.....#..#..#......#.......#.........#.#.......#....#........#.....#.#...#................#...
............#....#.........#.#..............##..................................#.#.......#.#..........#...#..#.#......##..#.......
..................#...##............#.....#.....#.....#......................#..#.............................#....##..#...#.#.....
............#.............#.........#........................##..............#.#....#.............#..........#.....#...............
................#..#...##........#...#............#..................#.........#.....#..............#....#................#........
.#...#...#..#.#...#............#....#..#.#.........#............#.#.#..#..................#.##....#.............#..................
....#..#....#......#..#..##...#.#..#...##.........................#...................#..........#..#.......#...##.....#.....#.....
....................#..........................##................................#.....................#................#.....#.##.
..............#..............#..#..#.......#....#....................................#.........#..........#.#...............#.##...
........#......#.#.........#.......#..........#..................................................................#........#..#..#..
.................#.......##.......##......#..................#..#.......#....................#....#............#.......#.......#.#.
.....##.......#......#...#.#....#..#.................#.#....#.....#.............................#..#.........#.#.................#.
.......................#.....#...##...##..................................#....................##....##..........#..#..............
.#.......#....##.....#........#..............................#.....#....#.....................#........#..#..#.......#.#....#....#.
....#..#............#.........#...........................#.........##....#..#...................#..............#........#......##.
......##.................#..#.....................#...........................#.........................#...................#......
.....#...##.........#........#.##....###..................#........#..........................#.####................#.....#...#....
.#....#...#........#....#.............#................#.................##...#....#................#..#...#.....#............#....
....##.#.#.....#......#.......##.....#..........#........#..............#...#....#.................#.....#....#....................
.....#..............#.##..#.......#..........##..........................#.#.........#..........#....##....#.........#.#...........
.....#..#........#.#..........#...#.................#...........#.....#.........................#.#............#...................
.......#...........#..........#......................#........................##.....##............#........#..................##..
....#........................................#..#.....................#...#.#...#......................#...#....#................#.
....#.##......#........#.....................#.........#...................#...#....#.#..............###..................###......
..#...........#.....#....#..#.#............#...........#........#.....#.#................................#.......##....##..........
...##.###.....................#............#.....#..#.#..............##..#.##..#.....#...................#.#......#....#...........
.##....#............#....#.............#...#.#.............#..##.............#......................##.##..................#..#....
...#.....##.........#..##..............#..#........##..#.#................#...#.#.#....#..................#..............#.........
..........#....#.#.....#.................#...#............#.#......#...........#..........##..#...............#...#...##..#.#......
..............#.....................#....#..#.##...#.......#.#..#.....#..................#................#........................
......#.#.......#.....#...........##.................#......#........#.#........#..........#..##.........#...#.......#..#..........
........................#..........#..#..................#...................#..#..##...##..#...................#.............#....
...............#...#......................#....#...#..............##....#......#......#...#..#.....................................
......#...#...###..#..#...................#...#.#............#......#...##....#.........#..#.....#.........#.#........##...........
.#...#.........................##..##................#.....##.#...#........#.....#..#....##.........#..................#..#........
..#......#.........#..........##..#......##.#................................................#.......#.........................#.#.
......#....#..#.#..#.............#..............#.........#........#.....#.#..#......#.#.........................#..............#..
.........................................#........#..................#...##.......#..........#........#..........#..#..............
..#..........#............................#...#.....#....#..................#......................#.#..........#.##......#...#....
...........................................#.....#..#....#........#.....#........#......#...#...................................#..
..#..#...#.#..................#.#.............#..........#....#.....#......#......##.#..#...#.##....#....................#.....#...
..#..##..........................#........#....#..........#........#..........#..#.#..............#..#......................#.#....
....#...#.#.#..........#......................................#.......#...................##..#..#..................#.....#........
............................#............##.#..............#.......#.#...#....#.........#....#......#........................#.....
..#.........#...............#.......#....#..........#.....#.................#..#...##.#......................................#.....
.......#...#.................#..................#......#....#..##...#.........#.#.#..........#...##..#.#...................#.......
.........................#.............#....#...#.#.#....#.....#...............#........#.#...#..#..........#............#.........
.......##.............##............#..###..#.#..#..##....#...#......##..#...#........#....#..#..........#..#..#..........#........
..#..............#..##.......#...#........##.......................#..................#...........##........#.#..............#.....
.#...#.............................#.#.......#....................#.......#..........#...................#....#...##...............
..................####.#............###.....#.##..#...............#.............#..#..........#...............................#..#.
.....................#....#.......#......#......#......#..................#..#....#..........#....#..............#..#..............
.............#.#.##..#..#.....#.....##........##..#.#.........#......#..#.........##......#........#.........#...#...#.............
.#..........#..#.........#...#..##.........#........###......#....##...........#......#.#......................#.....#.............
..#.........##.#..#.#..........#.............................#.............##......#..#.............#.....#...#....#...............
.#......................#.....................###..#.#.....#..........#..#.#.#....#.......#..#.........#...........................
..........#......#....#..#....##..........#..........#.#...................#.................#....#.....#......#..........#........
.........................#.....#.....#........................#.........#.#...#............................#.....#.................
........#........#.........................##...............#.#.#......#......#......#..#.........#.....#.................#........
...............##..........#...........................#.....#....#.....#.#...................#.............#...............#......
.................................................................S.................................................................
.................##...#....#..........#..##..##..........#......#..#..............##...#.#......#......#......#..#.......#.........
..........#.........#.#...#..#....#.#.............#..#..#...........#.............#...........##.#...........#.......##............
........#............#.#..........#..##.#.#...............#.....#......#...#...#....#......#........#.............#.......#........
..........#...............#..#.................##.....#............#....###....#.............#................#...#................
.#..............#.....##.#....#...#..#.##.......................#.#....#.......#.#............#........#.....#..##...##............
.##.........#...................##.....#....#.......#.............##.......#...................#...........#.......#....#..........
............#..#...#.....#....#...........#.#......#.#..#.........#.#....#..................##............#........................
.............#..#...#....#......#......#......................#....#......###..........#..#.#..#...##....#..#......................
...#.........#..........#..#.........................##...........#......#............#..#.#.....##............#..#.#........#..#..
....#.#........##......................#.#.#.#..#.....#..#....##...#....##...#.#...#......#......................#.................
.....##..................#..........#.....##.....##..........#.#..#.......#.#...#.........#.......#..........#....#..........#.#...
...........................#..........#...#......#.#..#........#...#...............................#.#.#...#.....#..........#...##.
.....................#..##.##.....#......#.........#..##...#...............#.#.#........#..#...#...........#...#...................
..........#.........#..#.....#.......#.....###......#.....#.........#......#...............#.........#.........#...................
.......##..#..............#.........#.....#.......#...##.###...........#.#..........##.........................................#...
..#.....#..................#.#..........#..#..##....#...............#..............#.........##.........###.#...........#....##....
.#....#.....#.................#...#..........#.........#....#..............#.........##......#...#..........#........#.#.......#...
..............#.......................##.......##.......#..#.........#.....#....................................................#..
...#..#......#.............#....##..........#.#.......#...............#................###...#....#......#.........#.....#.....#...
....#..........#..........#..........#.....#..............#.......##......................#..#.#...............................#...
.#......#.....................................##.#..........................#.....#.#..#.#..........##.......................#...#.
......#........#.............#...........#.#............#.#.#...................#.##......#.#...................#....#..#..#.......
.#.........##.....#.............#...........#.......#.......#.....##..###.....#...........#.......................#.#..............
....##.........#.............................#.....##........#......#........#................#...#......................#.........
..................#...............##...............##.....#..#.#........#.....#.....#........#...#..#.........#.#.....#......#.#...
..................#.............##..#...............#....#.........##..#..........#......#....#.................##..#..#......#..#.
.........###.......#................#....##.....#...#...........#.............................#...#................#...............
...#......#...#...#...#...................#....#.#......#..#..#...#....#..#....................#..............#.................#..
......................#.............##..#....#...#..............#...................#..#.......#..............###................#.
..#........#.#............#..............#.......##......................#..............#..................#..#..#...........#.....
.#........#..............................#..........................................#..........#.......#.............#.#.......#...
.............#..#....#......#.......#.#.................................##...............................#....#......#.............
.#.#...#...#....#...#......#................#..#.......#..#.##..............#...........#....#.......#............#....#.........#.
...#.............#....#............................#........##.........##..........#..............................#.....#.......#..
....#......#....#......#...................#.........#.......##.......................#..................###........###.......#....
..........#...#......#........#..........#.........#.......#....#............#.....##......................#...........#..##..#.#..
.###.#.##......#.#........................#.#..#...................#.......#....#................##...#..#...#..#..#.###....#......
.....#.#......................................#.............#......#............................#..................................
..................#...............##.................#.........................#.................#.......#..##.#..##.....#..#......
...........#.........#.#...#....#.......................#.........#............#.#...#............##............#..................
.....#........#.............#..#..................#..#......#...#.#.......#.....................#..................................
..................#.#..............##..........#..........##....................................#.#............#.#.....#........#..
.....#.#.##....#..............#..........................#......#....#...#.....................................#...#..#.#.....#....
....#.#.........##.....................#...........................#......#.......#........#.#.#..#..#.......#....#..#......#...#..
............#.......#.............#......#...............#......#.##.....#..#......................#....#.....#...........#..##....
...#...#....#..#...##.......#.....#.....................##.....#..............#.............#...#....#..##.#....#........###..#....
.....#..............#....#.......#..........................#..........................#..##.....#...##................##..........
...#........#..#.#............##............#.........###....#.#.....#....#.............##................#.......#..##.......#.#..
...........#.........#..#...........#...................#......#.....#.....................#...........#.....#.....................
...#..#...##...............#..................#.............##......##...............#...#............#.........#..#...#.......#...
......#...........#............##.#.#...#...............#..#......##...........................#...#..#.#.......#.....#.........##.
...........#.#..#................#.......#......#............#..#.....#...............#....#.......#.#..#.#......#....#............
...#..............................................................#................#.....#.........................................
.................##.....................#.#....#..............#....................................#..............#.#..............
.............##.............#..##..................#..............#............#.................#........................#.#......
...........................#.....#..#..##.....##............#..#.......................#.....#..#.....#..#.....#........#....#.....
..........#.................#........#.......................................#.#...#..###...###.#...........#...#..................
..#....#.........#....#.........#....#.....#...................#............#....#.......#...#......#......#.#..........##..#......
...#........................#..#...........#...##..........................###................#.#.......#..................#.......
.......#.#............#.......#.....#.............................#.........#......#......................#........#...#.......#...
.#.#..#.........................#..........#......................................#...........#..#...............#......##.........
...#..............#......#.##....##.#...#..........##............................#.#.#........#.#........#....##.............#.....
....................#...............#..#........#...........................................##..........#.#.....#....#.#...#.......
.......................#........##..............#........#....................#.......#...#....#...........##........#....#.....#..
...................................................................................................................................

115
day-21/src/bin/part1.rs Normal file
View File

@ -0,0 +1,115 @@
use itertools::Itertools;
fn main() {
println!("{}", part1(include_str!("./input.txt"), 64));
}
fn part1(input: &str, steps: u32) -> usize {
let map = input
.lines()
.map(|line| line.chars().map(Plot::from).collect())
.collect::<Vec<Vec<_>>>();
let starting = map
.iter()
.enumerate()
.find_map(|(y, l)| {
l.iter().enumerate().find_map(|(x, p)| {
if p == &Plot::Starting {
Some((x, y))
} else {
None
}
})
})
.expect("no starting plot");
let reachable = std::iter::successors(Some(vec![(starting, 0)]), |prev| {
let next = prev
.iter()
.flat_map(|p| {
successors(*p, &map)
.into_iter()
.filter(|(_, cur_steps)| *cur_steps <= steps)
})
.sorted()
.dedup()
.collect::<Vec<_>>();
if next.is_empty() {
None
} else {
Some(next)
}
})
.collect::<Vec<_>>();
reachable.last().expect("no last element").len()
}
fn successors(
((x, y), step_count): ((usize, usize), u32),
map: &Vec<Vec<Plot>>,
) -> Vec<((usize, usize), u32)> {
let mut successors = vec![];
if x > 0 && map[y][x - 1] != Plot::Stone {
successors.push(((x - 1, y), step_count + 1));
}
if y > 0 && map[y - 1][x] != Plot::Stone {
successors.push(((x, y - 1), step_count + 1));
}
if x < map[0].len() - 1 && map[y][x + 1] != Plot::Stone {
successors.push(((x + 1, y), step_count + 1));
}
if y < map.len() - 1 && map[y + 1][x] != Plot::Stone {
successors.push(((x, y + 1), step_count + 1));
}
successors
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Plot {
Starting,
Garden,
Stone,
}
impl From<char> for Plot {
fn from(c: char) -> Self {
match c {
'.' => Plot::Garden,
'#' => Plot::Stone,
'S' => Plot::Starting,
_ => panic!("Invalid plot"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use indoc::indoc;
#[test]
fn test_part1() {
assert_eq!(
part1(
indoc!(
"
...........
.....###.#.
.###.##..#.
..#.#...#..
....#.#....
.##..S####.
.##..#...#.
.......##..
.##.#.####.
.##..##.##.
...........
"
),
6
),
16
);
}
}

303
day-21/src/bin/part2.rs Normal file
View File

@ -0,0 +1,303 @@
use itertools::Itertools;
use std::collections::{HashMap, HashSet, VecDeque};
fn main() {
println!("{}", part2(include_str!("./input.txt"), 26501365));
}
/// Assumptions for part 2:
/// Line and column of the starting point are completely empty
/// Borders are completely empty
/// The garden is of odd size with the starting point in the middle
/// The garden is a square
/// The step count is a whole number of the gardens width plus half the width
fn part2(input: &str, steps: u32) -> usize {
/* IDEA:
the inner repetitions of the garden have all the same amount of reachable plots,
grouped by whether they are entered with an odd or even amount of steps.
The corners of this diagonal square of reachable plots have the size of the
garden minus one steps remaining and are different from each other.
the small triangles have half the size of the garden minus one steps remaining
and are entered from the corners.
the big triangles have the size of the garden plus half the size of the garden
of steps remaining and are also entered from the corners.
*/
let map = input
.lines()
.map(|line| line.chars().map(Plot::from).collect())
.collect::<Vec<Vec<_>>>();
assert!(map.len() == map[0].len(), "garden is not a square");
assert!(
steps as usize % map.len() == map.len() / 2,
"steps is not a whole number of the gardens width plus half the width"
);
let starting = map
.iter()
.enumerate()
.find_map(|(y, l)| {
l.iter().enumerate().find_map(|(x, p)| {
if p == &Plot::Starting {
Some((x, y))
} else {
None
}
})
})
.expect("no starting plot");
assert!(
starting.0 == map.len() / 2 && starting.1 == map.len() / 2,
"starting point is not in the middle of the garden"
);
let grid_width = steps as usize / map.len() - 1;
// round down to even number
let odd_grids_amount = (grid_width / 2 * 2 + 1).pow(2);
let even_grids_amount = ((grid_width + 1) / 2 * 2).pow(2);
let odd_points_each = fill(starting, map.len() as u32 * 2 + 1, &map);
let even_points_each = fill(starting, map.len() as u32 * 2, &map);
let top_corner_points = fill((starting.0, map.len() - 1), map.len() as u32 - 1, &map);
let right_corner_points = fill((0, starting.1), map.len() as u32 - 1, &map);
let bottom_corner_points = fill((starting.0, 0), map.len() as u32 - 1, &map);
let left_corner_points = fill((map.len() - 1, starting.1), map.len() as u32 - 1, &map);
let corner_points =
top_corner_points + right_corner_points + bottom_corner_points + left_corner_points;
let small_top_right_points = fill((0, map.len() - 1), map.len() as u32 / 2 - 1, &map);
let small_top_left_points = fill(
(map.len() - 1, map.len() - 1),
map.len() as u32 / 2 - 1,
&map,
);
let small_bottom_right_points = fill((0, 0), map.len() as u32 / 2 - 1, &map);
let small_bottom_left_points = fill((map.len() - 1, 0), map.len() as u32 / 2 - 1, &map);
let small_points = (small_top_right_points
+ small_top_left_points
+ small_bottom_right_points
+ small_bottom_left_points)
* (grid_width + 1);
let large_top_right_points = fill((0, map.len() - 1), map.len() as u32 * 3 / 2 - 1, &map);
let large_top_left_points = fill(
(map.len() - 1, map.len() - 1),
map.len() as u32 * 3 / 2 - 1,
&map,
);
let large_bottom_right_points = fill((0, 0), map.len() as u32 * 3 / 2 - 1, &map);
let large_bottom_left_points = fill((map.len() - 1, 0), map.len() as u32 * 3 / 2 - 1, &map);
let large_points = (large_top_right_points
+ large_top_left_points
+ large_bottom_right_points
+ large_bottom_left_points)
* grid_width;
odd_grids_amount * odd_points_each
+ even_grids_amount * even_points_each
+ corner_points
+ small_points
+ large_points
}
fn fill((starting_x, starting_y): (usize, usize), steps: u32, map: &Vec<Vec<Plot>>) -> usize {
let mut ans = HashSet::new();
let mut seen = HashSet::new();
seen.insert((starting_x, starting_y));
let mut queue = VecDeque::new();
queue.push_back(((starting_x, starting_y), steps));
while let Some(((x, y), remaining_steps)) = queue.pop_front() {
if remaining_steps % 2 == 0 {
ans.insert((x, y));
}
if remaining_steps == 0 {
continue;
}
let directions = [
Some((x + 1, y)),
x.checked_sub(1).map(|x| (x, y)),
Some((x, y + 1)),
y.checked_sub(1).map(|y| (x, y)),
];
for (nx, ny) in directions.into_iter().flatten() {
if ny >= map.len()
|| nx >= map[0].len()
|| seen.contains(&(nx, ny))
|| map[ny][nx] == Plot::Stone
{
continue;
}
seen.insert((nx, ny));
queue.push_back(((nx, ny), remaining_steps - 1))
}
}
ans.len()
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
enum Plot {
Starting,
Garden,
Stone,
}
impl From<char> for Plot {
fn from(c: char) -> Self {
match c {
'.' => Plot::Garden,
'#' => Plot::Stone,
'S' => Plot::Starting,
_ => panic!("Invalid plot"),
}
}
}
#[allow(dead_code)]
/// Bruteforce
/// Takes too long
fn part2_bruteforce(input: &str, steps: u32) -> usize {
let map = input
.lines()
.map(|line| line.chars().map(Plot::from).collect())
.collect::<Vec<Vec<_>>>();
let starting = map
.iter()
.enumerate()
.find_map(|(y, l)| {
l.iter().enumerate().find_map(|(x, p)| {
if p == &Plot::Starting {
Some((x as i128, y as i128))
} else {
None
}
})
})
.expect("no starting plot");
let mut visited = HashSet::new();
visited.insert(starting);
let mut new = HashSet::new();
new.insert(starting);
let mut cache = HashMap::new();
cache.insert(0, 1);
let reachable = std::iter::successors(Some(vec![(starting, 0)]), |prev| {
let next = prev
.iter()
.flat_map(|p| {
successors(*p, &map)
.into_iter()
.filter(|(_, cur_steps)| *cur_steps <= steps)
})
.sorted()
.dedup()
.collect::<Vec<_>>();
if next.is_empty() {
None
} else {
Some(next)
}
})
.collect::<Vec<_>>();
reachable.last().expect("no last element").len()
}
fn successors(
((x, y), step_count): ((i128, i128), u32),
map: &Vec<Vec<Plot>>,
) -> Vec<((i128, i128), u32)> {
let height = map.len();
let width = map[0].len();
let ux = (x.rem_euclid(width as i128)) as usize;
let uy = (y.rem_euclid(height as i128)) as usize;
let mut successors = vec![];
if (ux > 0 && map[uy][ux - 1] != Plot::Stone) || (ux == 0 && map[uy][width - 1] != Plot::Stone)
{
successors.push(((x - 1, y), step_count + 1));
}
if (uy > 0 && map[uy - 1][ux] != Plot::Stone) || (uy == 0 && map[height - 1][ux] != Plot::Stone)
{
successors.push(((x, y - 1), step_count + 1));
}
if (ux < width - 1 && map[uy][ux + 1] != Plot::Stone)
|| (ux == width - 1 && map[uy][0] != Plot::Stone)
{
successors.push(((x + 1, y), step_count + 1));
}
if (uy < height - 1 && map[uy + 1][ux] != Plot::Stone)
|| (uy == height - 1 && map[0][ux] != Plot::Stone)
{
successors.push(((x, y + 1), step_count + 1));
}
successors
}
#[cfg(test)]
mod tests {
use super::*;
use indoc::indoc;
const INPUT: &str = indoc!(
"
...........
.....###.#.
.###.##..#.
..#.#...#..
....#.#....
.##..S####.
.##..#...#.
.......##..
.##.#.####.
.##..##.##.
...........
"
);
#[test]
#[ignore = "not working because of assumptions"]
fn test_part2_6() {
assert_eq!(part2(INPUT, 6), 16);
}
#[test]
#[ignore = "not working because of assumptions"]
fn test_part2_10() {
assert_eq!(part2(INPUT, 10), 50);
}
#[test]
#[ignore = "not working because of assumptions"]
fn test_part2_50() {
assert_eq!(part2(INPUT, 50), 1594);
}
#[test]
#[ignore = "not working because of assumptions"]
fn test_part2_100() {
assert_eq!(part2(INPUT, 100), 6536);
}
#[test]
#[ignore = "not working because of assumptions"]
fn test_part2_500() {
assert_eq!(part2(INPUT, 500), 167004);
}
#[test]
#[ignore = "not working because of assumptions"]
fn test_part2_1000() {
assert_eq!(part2(INPUT, 1000), 668697);
}
#[test]
#[ignore = "not working because of assumptions"]
fn test_part2_5000() {
assert_eq!(part2(INPUT, 5000), 16733044);
}
}