day21 solution
parent
59e06d73eb
commit
562cd63d87
|
@ -0,0 +1,128 @@
|
|||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
use std::collections::{HashMap, VecDeque};
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
|
||||
struct Point(usize, usize);
|
||||
|
||||
type Map = [[char; 131]; 131];
|
||||
|
||||
#[aoc_generator(day21)]
|
||||
fn parse(input: &str) -> (Point, Map) {
|
||||
let mut m = [['#'; 131]; 131];
|
||||
let mut start: Point = Point(0, 0);
|
||||
for (x, line) in input.lines().enumerate() {
|
||||
if line.is_empty() {
|
||||
continue;
|
||||
}
|
||||
for (y, t) in line.chars().enumerate() {
|
||||
match t {
|
||||
'.' => m[x][y] = '.',
|
||||
'#' => {}
|
||||
'S' => {
|
||||
start.0 = x;
|
||||
start.1 = y;
|
||||
m[x][y] = '.';
|
||||
}
|
||||
n @ _ => panic!("bad map char {}", n),
|
||||
}
|
||||
}
|
||||
}
|
||||
(start, m)
|
||||
}
|
||||
|
||||
fn infinite_step(start: &Point, map: &Map) -> HashMap<Point, usize> {
|
||||
let mut visited: HashMap<Point, usize> = HashMap::new();
|
||||
let mut frontier: VecDeque<(Point, usize)> = VecDeque::new();
|
||||
frontier.push_back((*start, 0));
|
||||
|
||||
while let Some((cur, dist)) = frontier.pop_front() {
|
||||
if visited.contains_key(&cur) {
|
||||
continue;
|
||||
}
|
||||
|
||||
visited.insert(cur, dist);
|
||||
|
||||
let x = cur.0;
|
||||
let y = cur.1;
|
||||
if x > 0 && map[x - 1][y] == '.' {
|
||||
let p = Point(x - 1, y);
|
||||
if !visited.contains_key(&p) {
|
||||
frontier.push_back((p, dist + 1));
|
||||
}
|
||||
}
|
||||
if x < map.len() - 1 && map[x + 1][y as usize] == '.' {
|
||||
let p = Point(x + 1, y);
|
||||
if !visited.contains_key(&p) {
|
||||
frontier.push_back((p, dist + 1));
|
||||
}
|
||||
}
|
||||
if y > 0 && map[x][y - 1] == '.' {
|
||||
let p = Point(x, y - 1);
|
||||
if !visited.contains_key(&p) {
|
||||
frontier.push_back((p, dist + 1));
|
||||
}
|
||||
}
|
||||
if y < map[x].len() - 1 && map[x][y + 1] == '.' {
|
||||
let p = Point(x, y + 1);
|
||||
if !visited.contains_key(&p) {
|
||||
frontier.push_back((p, dist + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
visited
|
||||
}
|
||||
|
||||
#[aoc(day21, part1)]
|
||||
fn part1(input: &(Point, Map)) -> usize {
|
||||
let visited = infinite_step(&input.0, &input.1);
|
||||
visited
|
||||
.values()
|
||||
.filter(|t| **t <= 64 && **t % 2 == 0)
|
||||
.count()
|
||||
}
|
||||
|
||||
#[aoc(day21, part2)]
|
||||
fn part2(input: &(Point, Map)) -> usize {
|
||||
let visited = infinite_step(&input.0, &input.1);
|
||||
|
||||
let even_corners = visited
|
||||
.values()
|
||||
.filter(|v| **v % 2 == 0 && **v > 65)
|
||||
.count();
|
||||
let odd_corners = visited
|
||||
.values()
|
||||
.filter(|v| **v % 2 == 1 && **v > 65)
|
||||
.count();
|
||||
|
||||
let even_full = visited.values().filter(|v| **v % 2 == 0).count();
|
||||
let odd_full = visited.values().filter(|v| **v % 2 == 1).count();
|
||||
|
||||
let n = ((26501365 - (input.1.len() / 2)) / input.1.len()) as usize;
|
||||
assert_eq!(n, 202300);
|
||||
|
||||
((n + 1) * (n + 1)) * odd_full + (n * n) * even_full - (n + 1) * odd_corners + n * even_corners
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
const SAMPLE_DATA: &'static str = r#"...........
|
||||
.....###.#.
|
||||
.###.##..#.
|
||||
..#.#...#..
|
||||
....#.#....
|
||||
.##..S####.
|
||||
.##..#...#.
|
||||
.......##..
|
||||
.##.#.####.
|
||||
.##..##.##.
|
||||
..........."#;
|
||||
|
||||
#[test]
|
||||
fn sample_data() {
|
||||
let input = parse(&SAMPLE_DATA);
|
||||
assert_eq!(part1(&input), 42);
|
||||
}
|
||||
}
|
|
@ -20,5 +20,6 @@ mod day17;
|
|||
mod day18;
|
||||
mod day19;
|
||||
mod day20;
|
||||
mod day21;
|
||||
|
||||
aoc_lib! { year = 2023 }
|
||||
|
|
Loading…
Reference in New Issue