advent-of-code-2023/src/day16.rs

151 lines
3.9 KiB
Rust

use std::io;
#[derive(PartialEq)]
enum Dir {
North,
South,
East,
West,
}
fn visit(board: &Vec<Vec<char>>, x: i64, y: i64, dir: Dir, visited: &mut Vec<Vec<(bool, bool)>>) {
if x < 0 || x >= board.len() as i64 {
return;
}
if y < 0 || y >= board[x as usize].len() as i64 {
return;
}
match board[x as usize][y as usize] {
'.' => match dir {
Dir::North | Dir::South => {
if visited[x as usize][y as usize].0 {
return;
}
visited[x as usize][y as usize].0 = true;
if dir == Dir::North {
visit(board, x - 1, y, dir, visited);
} else {
visit(board, x + 1, y, dir, visited);
}
}
Dir::West | Dir::East => {
if visited[x as usize][y as usize].1 {
return;
}
visited[x as usize][y as usize].1 = true;
if dir == Dir::West {
visit(board, x, y - 1, dir, visited);
} else {
visit(board, x, y + 1, dir, visited);
}
}
},
'\\' => {
visited[x as usize][y as usize].0 = true;
match dir {
Dir::North => visit(board, x, y - 1, Dir::West, visited),
Dir::South => visit(board, x, y + 1, Dir::East, visited),
Dir::West => visit(board, x - 1, y, Dir::North, visited),
Dir::East => visit(board, x + 1, y, Dir::South, visited),
}
}
'/' => {
visited[x as usize][y as usize].0 = true;
match dir {
Dir::North => visit(board, x, y + 1, Dir::East, visited),
Dir::South => visit(board, x, y - 1, Dir::West, visited),
Dir::West => visit(board, x + 1, y, Dir::South, visited),
Dir::East => visit(board, x - 1, y, Dir::North, visited),
}
}
'|' => {
visited[x as usize][y as usize].0 = true;
match dir {
Dir::North => visit(board, x - 1, y, Dir::North, visited),
Dir::South => visit(board, x + 1, y, Dir::South, visited),
Dir::West | Dir::East => {
visit(board, x + 1, y, Dir::South, visited);
visit(board, x - 1, y, Dir::North, visited);
}
}
}
'-' => {
visited[x as usize][y as usize].0 = true;
match dir {
Dir::North | Dir::South => {
visit(board, x, y + 1, Dir::East, visited);
visit(board, x, y - 1, Dir::West, visited);
}
Dir::West => visit(board, x, y - 1, Dir::West, visited),
Dir::East => visit(board, x, y + 1, Dir::East, visited),
}
}
c => panic!("Unhandled character {}", c),
}
}
fn count_energized(board: &Vec<Vec<char>>, locx: i64, locy: i64, dir: Dir) -> usize {
let mut visited = Vec::new();
for _ in 0..board.len() {
visited.push(vec![(false, false); board[0].len()]);
}
visit(board, locx, locy, dir, &mut visited);
visited
.iter()
.fold(0, |acc, v| acc + v.iter().filter(|(a, b)| *a || *b).count())
}
pub fn solve() -> usize {
let mut buffer = String::new();
while io::stdin().read_line(&mut buffer).unwrap() > 0 {}
count_energized(
&buffer
.trim()
.split("\n")
.map(|s| s.chars().collect())
.collect(),
0,
0,
Dir::East,
)
}
fn best_case(board: &Vec<Vec<char>>) -> usize {
let mut best = 0;
for r in 0..board.len() {
best = best.max(count_energized(board, r as i64, 0, Dir::East));
best = best.max(count_energized(
board,
r as i64,
(board[r].len() - 1) as i64,
Dir::West,
));
}
for c in 0..board[0].len() {
best = best.max(count_energized(board, 0, c as i64, Dir::South));
best = best.max(count_energized(
board,
(board.len() - 1) as i64,
c as i64,
Dir::North,
));
}
best
}
pub fn find_best() -> usize {
let mut buffer = String::new();
while io::stdin().read_line(&mut buffer).unwrap() > 0 {}
let board = buffer
.trim()
.split("\n")
.map(|s| s.chars().collect())
.collect();
best_case(&board)
}