1
0
Files
advent-of-rust-2024/src/day06.rs
2024-12-06 17:22:57 +01:00

126 lines
2.8 KiB
Rust

use std::{collections::HashSet, fs::read_to_string};
use crate::utils::grid::{Coord, Grid};
pub fn day_main() {
let input = read_to_string("input/day06.txt").unwrap();
let input = input.trim();
println!(" part1: {}", part1(input));
println!(" part2: {}", part2(input));
}
type RiddleResult = usize;
fn part1(input: &str) -> RiddleResult {
let (m, pos) = parse(input);
let dir = '^';
let visited = get_visited(&m, pos, dir);
visited.len()
}
fn get_visited(m: &Grid<char>, mut pos: Coord, mut dir: char) -> HashSet<Coord> {
let mut visited = HashSet::new();
while m.contains_key(pos) {
let (x, y) = pos;
visited.insert(pos);
let next = match dir {
'^' => (x, y - 1),
'v' => (x, y + 1),
'<' => (x - 1, y),
'>' => (x + 1, y),
_ => unreachable!(),
};
if m.contains_key(next) && '#' == m[next] {
dir = match dir {
'^' => '>',
'v' => '<',
'<' => '^',
'>' => 'v',
_ => unreachable!("asdf"),
};
} else {
pos = next;
}
}
visited
}
fn part2(input: &str) -> RiddleResult {
let (m, pos) = parse(input);
let dir = '^';
get_visited(&m, pos, dir)
.into_iter()
.filter(|open| is_loop(&m, *open, pos, dir))
.count()
}
fn parse(input: &str) -> (Grid<char>, Coord) {
let mut m = Grid::parse(input);
let start = m.entries().find(|(_, c)| **c == '^').unwrap().0;
m[start] = '.';
(m, start)
}
fn is_loop(m: &Grid<char>, block: Coord, mut pos: Coord, mut dir: char) -> bool {
let mut visited = HashSet::new();
loop {
let (x, y) = pos;
let next = match dir {
'^' => (x, y - 1),
'v' => (x, y + 1),
'<' => (x - 1, y),
'>' => (x + 1, y),
_ => unreachable!(),
};
if !m.contains_key(next) {
return false;
} else if next == block || '#' == m[next] {
// we only check for loops on a collision to speed things up
if visited.contains(&(pos, dir)) {
return true;
}
visited.insert((pos, dir));
dir = match dir {
'^' => '>',
'v' => '<',
'<' => '^',
'>' => 'v',
_ => unreachable!("asdf"),
};
} else {
pos = next;
}
}
}
#[cfg(test)]
mod test {
use super::{part1, part2};
const TEST_INPUT: &str = r"....#.....
.........#
..........
..#.......
.......#..
..........
.#..^.....
........#.
#.........
......#...
";
#[test]
fn test1() {
assert_eq!(part1(TEST_INPUT), 41);
}
#[test]
fn test2() {
assert_eq!(part2(TEST_INPUT), 6);
}
}