day(21): add solution
Signed-off-by: Matej Focko <me@mfocko.xyz>
This commit is contained in:
parent
b6381d38d7
commit
45603e36bf
2 changed files with 122 additions and 0 deletions
11
samples/day21.txt
Normal file
11
samples/day21.txt
Normal file
|
@ -0,0 +1,11 @@
|
|||
...........
|
||||
.....###.#.
|
||||
.###.##..#.
|
||||
..#.#...#..
|
||||
....#.#....
|
||||
.##..S####.
|
||||
.##..#...#.
|
||||
.......##..
|
||||
.##.#.####.
|
||||
.##..##.##.
|
||||
...........
|
111
src/bin/day21.rs
Normal file
111
src/bin/day21.rs
Normal file
|
@ -0,0 +1,111 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use aoc_2023::*;
|
||||
use itertools::iproduct;
|
||||
|
||||
type Position = Vector2D<isize>;
|
||||
|
||||
lazy_static! {
|
||||
static ref DIRECTIONS: Vec<Position> = vec![
|
||||
Position::new(0, 1),
|
||||
Position::new(0, -1),
|
||||
Position::new(1, 0),
|
||||
Position::new(-1, 0),
|
||||
];
|
||||
}
|
||||
const WIDTH: isize = 131;
|
||||
|
||||
fn _mod(n: isize, m: isize) -> isize {
|
||||
(m + (n % m)) % m
|
||||
}
|
||||
|
||||
type Output1 = usize;
|
||||
type Output2 = f64;
|
||||
|
||||
struct Steps<'a> {
|
||||
plots: &'a HashSet<Position>,
|
||||
positions: HashSet<Position>,
|
||||
}
|
||||
|
||||
impl<'a> Steps<'a> {
|
||||
fn new(plots: &'a HashSet<Position>) -> Self {
|
||||
Self {
|
||||
plots,
|
||||
positions: HashSet::from([Position::new(65, 65)]),
|
||||
}
|
||||
}
|
||||
|
||||
fn move_gardener(&mut self) {
|
||||
let mut next_positions = HashSet::new();
|
||||
|
||||
for (&pos, &dir) in iproduct!(self.positions.iter(), DIRECTIONS.iter()) {
|
||||
let next_pos = pos + dir;
|
||||
let cropped = Position::new(_mod(next_pos.x(), WIDTH), _mod(next_pos.y(), WIDTH));
|
||||
if self.plots.contains(&cropped) {
|
||||
next_positions.insert(next_pos);
|
||||
}
|
||||
}
|
||||
|
||||
self.positions = next_positions;
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Steps<'a> {
|
||||
type Item = usize;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let current = self.positions.len();
|
||||
self.move_gardener();
|
||||
Some(current)
|
||||
}
|
||||
}
|
||||
|
||||
struct Day21 {
|
||||
plots: HashSet<Position>,
|
||||
}
|
||||
impl Solution<Output1, Output2> for Day21 {
|
||||
fn new<P: AsRef<Path>>(pathname: P) -> Self {
|
||||
let lines: Vec<String> = file_to_lines(pathname);
|
||||
|
||||
let plots = (0_isize..)
|
||||
.zip(lines.iter())
|
||||
.flat_map(move |(y, row)| {
|
||||
(0_isize..).zip(row.chars()).filter_map(move |(x, c)| {
|
||||
if c != '#' {
|
||||
Some(Position::new(x, y))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
|
||||
Self { plots }
|
||||
}
|
||||
|
||||
fn part_1(&mut self) -> Output1 {
|
||||
Steps::new(&self.plots).nth(64).unwrap()
|
||||
}
|
||||
|
||||
fn part_2(&mut self) -> Output2 {
|
||||
let steps = Steps::new(&self.plots).take(328).collect_vec();
|
||||
|
||||
let (x0, y0) = (65_f64, steps[65] as f64);
|
||||
let (x1, y1) = (196_f64, steps[196] as f64);
|
||||
let (x2, y2) = (327_f64, steps[327] as f64);
|
||||
|
||||
let y01 = (y1 - y0) / (x1 - x0);
|
||||
let y12 = (y2 - y1) / (x2 - x1);
|
||||
let y012 = (y12 - y01) / (x2 - x0);
|
||||
|
||||
let n = 26501365_f64;
|
||||
|
||||
y0 + y01 * (n - x0) + y012 * (n - x0) * (n - x1)
|
||||
}
|
||||
}
|
||||
|
||||
fn main() -> Result<()> {
|
||||
Day21::main()
|
||||
}
|
||||
|
||||
test_sample!(day_21, Day21, 0, 0);
|
Loading…
Reference in a new issue