AoC/2023/src/bin/day16.rs
2024-12-25 12:52:38 +01:00

96 lines
2.7 KiB
Rust

use std::{collections::{HashMap, HashSet}, cmp::max};
use aoc::grid::{GridVec, Grid};
use array2d::Array2D;
fn grid_position(grid: &GridVec, x: isize, y: isize) -> Option<(usize, usize)> {
if x < 0 || y < 0 {
return None;
}
let cur_x: usize = x.try_into().unwrap();
let cur_y: usize = y.try_into().unwrap();
if cur_x >= grid.width() || cur_y >= grid.height() {
return None;
}
return Some((cur_x, cur_y));
}
fn trace(grid: &GridVec, energized: &mut Array2D<bool>, cache: &mut HashMap<(isize, isize, isize, isize), ()>, mut x: isize, mut y: isize, mut dx: isize, mut dy: isize) {
let key = (x, y, dx, dy);
if let Some(cached) = cache.get(&key) {
println!("Cached result found for {:?}", key);
return *cached;
}
cache.insert(key, ());
let mut steps = HashSet::new();
while let Some((cur_x, cur_y)) = grid_position(grid, x, y) {
energized[(cur_y, cur_x)] = true;
let cur_ch = grid.char_at(cur_x, cur_y);
// println!("{x},{y} ({dx},{dy}) {cur_ch} ");
match cur_ch {
'/' => (dx, dy) = (-dy, -dx),
'\\' => (dx, dy) = (dy, dx),
'|' if dy == 0 => {
trace(grid, energized, cache, x, y - 1, 0, -1);
(dx, dy) = (0, 1);
}
'-' if dx == 0 => {
trace(grid, energized, cache, x - 1, y, -1, 0);
(dx, dy) = (1, 0);
},
'-' | '|' | '.' => {},
_ => panic!("Unknown character")
};
assert!(dx == 0 || dy == 0);
x += dx;
y += dy;
if !steps.insert((x, y, dx, dy)) {
println!("Loop detected, stopping");
break;
}
}
}
fn energized(grid: &GridVec, x: isize, y: isize, dx: isize, dy: isize) -> usize {
let mut energized = Array2D::filled_with(false, grid.height(), grid.width());
let mut cache = HashMap::new();
trace(&grid, &mut energized, &mut cache, x, y, dx, dy);
energized.elements_row_major_iter().filter(|energized| **energized).count()
}
fn main() {
let grid = GridVec::read();
let part1 = energized(&grid, 0, 0, 1, 0);
println!("Part 1: {part1}");
let mut part2 = 0;
let x_max: isize = grid.width().try_into().unwrap();
let y_max: isize = grid.height().try_into().unwrap();
for y in 0..y_max {
let a = energized(&grid, 0, y, 1, 0);
let b = energized(&grid, x_max - 1, y, -1, 0);
part2 = max(part2, max(a, b));
}
for x in 0..x_max {
let a = energized(&grid, x, 0, 0, 1);
let b = energized(&grid, x, y_max - 1, 0, -1);
part2 = max(part2, max(a, b));
}
println!("Part 2: {part2}");
}