solution: day 21

This commit is contained in:
Matej Janezic 2023-12-21 20:26:26 +01:00
parent 0000038000
commit 0000039019
Signed by: janezicmatej
GPG Key ID: 4298E230ED37B2C0
2 changed files with 117 additions and 0 deletions

11
data/examples/21.txt Normal file
View File

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

106
src/bin/21.rs Normal file
View File

@ -0,0 +1,106 @@
use std::{collections::HashSet, usize};
fn parse_input(input: &str) -> (Vec<Vec<u8>>, (isize, isize)) {
let mut grid: Vec<_> = input.lines().map(|x| x.as_bytes().to_vec()).collect();
let start = grid
.iter()
.enumerate()
.flat_map(|(y, item)| item.iter().enumerate().map(move |(x, item)| (x, y, *item)))
.find_map(|(x, y, s)| if s == b'S' { Some((y, x)) } else { None })
.unwrap();
grid[start.0][start.1] = b'.';
(grid, (start.0 as isize, start.1 as isize))
}
fn walk_return_at(
grid: &[Vec<u8>],
start: (isize, isize),
mut returns: Vec<usize>,
can_cycle: bool,
) -> Vec<usize> {
returns.sort_by(|a, b| b.cmp(a));
let h = grid.len() as isize;
let w = grid[0].len() as isize;
let invalid_indexing = |y, x| y < 0 || y >= h || x < 0 || x >= w;
let mut results = Vec::new();
let length = returns[0];
let mut next = returns.pop().unwrap();
let mut visited = HashSet::new();
visited.insert(start);
for i in 1..=length {
let mut new_visited = HashSet::new();
for (y, x) in visited.iter() {
for (dy, dx) in [(1, 0), (0, 1), (-1, 0), (0, -1)] {
let (ny, nx) = (y + dy, x + dx);
if !can_cycle && invalid_indexing(ny, nx) {
continue;
}
let (cy, cx) = (ny.rem_euclid(h) as usize, nx.rem_euclid(w) as usize);
if grid[cy][cx] == b'.' {
new_visited.insert((ny, nx));
}
}
}
visited = new_visited;
if i == next {
results.push(visited.len());
if !returns.is_empty() {
next = returns.pop().unwrap();
}
}
}
results
}
pub fn part_one(input: &str) -> Option<usize> {
let (grid, start) = parse_input(input);
let result = walk_return_at(&grid, start, vec![64], false);
Some(result[0])
}
pub fn part_two(input: &str) -> Option<usize> {
let (grid, start) = parse_input(input);
let h = grid.len();
let s = start.0 as usize;
let result = walk_return_at(&grid, start, vec![s, s + h, s + 2 * h], true);
let a = (result[2] - 2 * result[1] + result[0]) / 2;
let b = (result[1] - result[0]) - a;
let c = result[0];
let x = 26501365 / h;
Some(a * x * x + b * x + c)
}
aoc::solution!(21);
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_part_one() {
assert_eq!(
part_one(&aoc::template::read_file("examples", 21)),
Some(42)
);
}
}