221 lines
5.6 KiB
Rust
221 lines
5.6 KiB
Rust
use aoc_runner_derive::{aoc, aoc_generator};
|
|
use std::collections::HashSet;
|
|
|
|
#[aoc_generator(day16)]
|
|
fn parse(input: &str) -> Vec<Vec<char>> {
|
|
input
|
|
.lines()
|
|
.filter_map(|line| {
|
|
if !line.is_empty() {
|
|
Some(line.chars().collect())
|
|
} else {
|
|
None
|
|
}
|
|
})
|
|
.collect()
|
|
}
|
|
|
|
#[derive(Copy, Clone, Eq, PartialEq, Hash)]
|
|
enum Dir {
|
|
North,
|
|
East,
|
|
South,
|
|
West,
|
|
}
|
|
|
|
fn visited_spaces(
|
|
map: &[Vec<char>],
|
|
visited: &mut HashSet<(i64, i64, Dir)>,
|
|
start_x: i64,
|
|
start_y: i64,
|
|
start_dir: Dir,
|
|
depth: usize,
|
|
) {
|
|
if start_x < 0
|
|
|| start_y < 0
|
|
|| start_x as usize > (map.len() - 1)
|
|
|| start_y as usize > (map[0].len() - 1)
|
|
{
|
|
return;
|
|
}
|
|
let mut x = start_x;
|
|
let mut y = start_y;
|
|
let mut dir = start_dir;
|
|
if visited.contains(&(x, y, dir)) {
|
|
return;
|
|
}
|
|
loop {
|
|
let now = (x, y, dir);
|
|
if visited.contains(&now) {
|
|
return;
|
|
} else {
|
|
visited.insert((x, y, dir));
|
|
}
|
|
match dir {
|
|
Dir::North => match map[x as usize][y as usize] {
|
|
'/' => dir = Dir::East,
|
|
'\\' => dir = Dir::West,
|
|
'|' => {}
|
|
'-' => {
|
|
visited_spaces(map, visited, x, y, Dir::West, depth + 1);
|
|
dir = Dir::East;
|
|
}
|
|
'.' => {}
|
|
n @ _ => panic!("unknown map piece {}", n),
|
|
},
|
|
Dir::South => match map[x as usize][y as usize] {
|
|
'/' => dir = Dir::West,
|
|
'\\' => dir = Dir::East,
|
|
'|' => {}
|
|
'-' => {
|
|
visited_spaces(map, visited, x, y, Dir::West, depth + 1);
|
|
dir = Dir::East;
|
|
}
|
|
'.' => {}
|
|
n @ _ => panic!("unknown map piece {}", n),
|
|
},
|
|
Dir::East => match map[x as usize][y as usize] {
|
|
'/' => dir = Dir::North,
|
|
'\\' => dir = Dir::South,
|
|
'|' => {
|
|
visited_spaces(map, visited, x, y, Dir::North, depth + 1);
|
|
dir = Dir::South;
|
|
}
|
|
'-' => {}
|
|
'.' => {}
|
|
n @ _ => panic!("unknown map piece {}", n),
|
|
},
|
|
Dir::West => match map[x as usize][y as usize] {
|
|
'/' => dir = Dir::South,
|
|
'\\' => dir = Dir::North,
|
|
'|' => {
|
|
visited_spaces(map, visited, x, y, Dir::North, depth + 1);
|
|
dir = Dir::South;
|
|
}
|
|
'-' => {}
|
|
'.' => {}
|
|
n @ _ => panic!("unknown map piece {}", n),
|
|
},
|
|
}
|
|
match dir {
|
|
Dir::North => {
|
|
x -= 1;
|
|
if x < 0 {
|
|
return;
|
|
}
|
|
}
|
|
Dir::South => {
|
|
x += 1;
|
|
if x as usize >= map.len() {
|
|
return;
|
|
}
|
|
}
|
|
Dir::East => {
|
|
y += 1;
|
|
if y as usize >= map[0].len() {
|
|
return;
|
|
}
|
|
}
|
|
Dir::West => {
|
|
y -= 1;
|
|
if y < 0 {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn energized_squares(visited: &HashSet<(i64, i64, Dir)>) -> usize {
|
|
let mut t: HashSet<(i64, i64)> = HashSet::new();
|
|
for i in visited.iter() {
|
|
t.insert((i.0, i.1));
|
|
}
|
|
t.len()
|
|
}
|
|
|
|
#[aoc(day16, part1)]
|
|
fn part1(input: &[Vec<char>]) -> usize {
|
|
let mut visited: HashSet<(i64, i64, Dir)> = HashSet::new();
|
|
visited_spaces(input, &mut visited, 0, 0, Dir::East, 0);
|
|
energized_squares(&visited)
|
|
}
|
|
|
|
#[aoc(day16, part2)]
|
|
fn part2(input: &[Vec<char>]) -> usize {
|
|
let mut max = 0;
|
|
let xlen = input.len() - 1;
|
|
let ylen = input[0].len() - 1;
|
|
|
|
for t in 0..=xlen {
|
|
let mut evisited: HashSet<(i64, i64, Dir)> = HashSet::new();
|
|
visited_spaces(input, &mut evisited, t as i64, 0, Dir::East, 0);
|
|
let emax = energized_squares(&evisited);
|
|
if emax > max {
|
|
max = emax;
|
|
}
|
|
|
|
let mut wvisited: HashSet<(i64, i64, Dir)> = HashSet::new();
|
|
visited_spaces(
|
|
input,
|
|
&mut wvisited,
|
|
xlen as i64,
|
|
(ylen - t) as i64,
|
|
Dir::West,
|
|
0,
|
|
);
|
|
let wmax = energized_squares(&wvisited);
|
|
if wmax > max {
|
|
max = wmax;
|
|
}
|
|
}
|
|
|
|
for t in 0..=ylen {
|
|
let mut svisited: HashSet<(i64, i64, Dir)> = HashSet::new();
|
|
visited_spaces(input, &mut svisited, 0, t as i64, Dir::South, 0);
|
|
let smax = energized_squares(&svisited);
|
|
if smax > max {
|
|
max = smax;
|
|
}
|
|
|
|
let mut nvisited: HashSet<(i64, i64, Dir)> = HashSet::new();
|
|
visited_spaces(
|
|
input,
|
|
&mut nvisited,
|
|
xlen as i64,
|
|
(ylen - t) as i64,
|
|
Dir::North,
|
|
0,
|
|
);
|
|
let nmax = energized_squares(&nvisited);
|
|
if nmax > max {
|
|
max = nmax;
|
|
}
|
|
}
|
|
|
|
max
|
|
}
|
|
|
|
#[cfg(test)]
|
|
mod tests {
|
|
use super::*;
|
|
|
|
const SAMPLE_DATA: &'static str = r#".|...\....
|
|
|.-.\.....
|
|
.....|-...
|
|
........|.
|
|
..........
|
|
.........\
|
|
..../.\\..
|
|
.-.-/..|..
|
|
.|....-|.\
|
|
..//.|...."#;
|
|
|
|
#[test]
|
|
fn sample_data() {
|
|
let input = parse(&SAMPLE_DATA);
|
|
assert_eq!(part1(&input), 46);
|
|
assert_eq!(part2(&input), 51);
|
|
}
|
|
}
|