Solved day 6

This commit is contained in:
2024-12-08 11:53:33 +01:00
parent 6e89cf1873
commit b45942fc9a

View File

@@ -1,11 +1,13 @@
use std::collections::HashSet;
use itertools::Itertools;
use crate::day_solver::DaySolver;
use crate::util::{Coord, Grid};
#[cfg(test)]
use crate::util::read_file;
pub struct Day6 {
maze: Grid<char>
maze: Grid<char>,
initial_path: Option<Vec<Coord<usize>>>
}
const DIRECTIONS: [Coord<isize>; 4] = [
@@ -15,6 +17,12 @@ const DIRECTIONS: [Coord<isize>; 4] = [
Coord { x: -1, y: 0 }
];
enum GuardResult {
Loop,
Walkout(Vec<Coord<usize>>),
Illegal
}
impl Day6 {
pub fn create(input: String) -> Self {
@@ -22,46 +30,101 @@ impl Day6 {
// Put the input into the day struct
Day6 {
maze: Grid::parse(input, None)
maze: Grid::parse(input, None),
initial_path: None
}
}
fn encode_dirs(prev_dirs: &u8, to_add: usize) -> u8 {
prev_dirs | 1 << to_add
}
fn has_dir(dirs: &u8, dir_to_check: usize) -> bool {
(dirs & 1 << dir_to_check) != 0
}
fn simulate_guard(maze: &Grid<char>) -> GuardResult {
let mut cur_pos = match maze.find(&'^') {
Some(pos) => pos,
None => return GuardResult::Illegal
};
let mut cur_direction_index = 0;
let mut cur_direction = DIRECTIONS[cur_direction_index];
let mut next_pos = cur_pos.add_signed(cur_direction);
let mut visited_positions = Vec::new();
let mut previous_directions: Grid<u8> = Grid {
data: vec![0; maze.width * maze.height()],
width: maze.width,
default: Some(0)
};
while maze.in_bounds(next_pos.x, next_pos.y) {
// println!("pos: {:?}", cur_pos);
let c = maze.get(next_pos.x, next_pos.y);
if c == &'#' {
cur_direction_index = (cur_direction_index + 1) % DIRECTIONS.len();
cur_direction = DIRECTIONS[cur_direction_index];
next_pos = cur_pos.add_signed(cur_direction);
} else {
let existing_dirs = previous_directions.get(cur_pos.x, cur_pos.y);
if Self::has_dir(existing_dirs, cur_direction_index) {
// println!("Loop detected at {:?}", cur_pos);
return GuardResult::Loop
}
previous_directions.set(cur_pos.x, cur_pos.y, Self::encode_dirs(existing_dirs, cur_direction_index));
cur_pos = next_pos;
visited_positions.push(cur_pos);
next_pos = cur_pos.add_signed(cur_direction);
}
}
GuardResult::Walkout(visited_positions)
}
}
impl DaySolver for Day6 {
fn solve_part1(&mut self) -> String {
let mut cur_pos = self.maze.find(&'^').unwrap();
let mut cur_direction_index = 0;
let mut cur_direction = DIRECTIONS[cur_direction_index];
let mut next_pos = cur_pos.add_signed(cur_direction);
let mut visited_positions = HashSet::new();
while self.maze.in_bounds(next_pos.x, next_pos.y) {
// println!("pos: {:?}", cur_pos);
let c = self.maze.get(next_pos.x, next_pos.y);
if c == &'#' {
cur_direction_index = (cur_direction_index + 1) % DIRECTIONS.len();
cur_direction = DIRECTIONS[cur_direction_index];
next_pos = cur_pos.add_signed(cur_direction);
} else {
cur_pos = next_pos;
visited_positions.insert(cur_pos);
next_pos = cur_pos.add_signed(cur_direction);
}
if let GuardResult::Walkout(path) = Self::simulate_guard(&self.maze) {
self.initial_path = Some(path.to_owned());
path.iter().unique().count().to_string()
} else {
panic!("The guard got stuck in the maze")
}
visited_positions.len().to_string()
}
fn solve_part2(&mut self) -> String {
// Idea so far:
// When walking the path as in part 1, for each position, check if the "next position" has been visited before, but while walking 1 rotation to the left
// If that is the case, then if we block the next position, the guard would rotate to go back into his original path
return 0.to_string();
let initial_path = match &self.initial_path {
Some(path) => path.to_owned(),
None => match Self::simulate_guard(&self.maze) {
GuardResult::Walkout(path) => {
self.initial_path = Some(path.to_owned());
path.to_owned()
},
GuardResult::Loop => panic!("The initial path does not leave the maze!"),
GuardResult::Illegal => panic!("You are BANDIT!")
}
};
let mut loop_count = 0;
// For each position that the guard visits, we check what will happen if it is blocked by a wall
for pos in initial_path.iter().unique() {
let mut new_maze= self.maze.clone();
new_maze.set(pos.x, pos.y, '#');
if let GuardResult::Loop = Self::simulate_guard(&new_maze) {
loop_count += 1;
}
}
loop_count.to_string()
}
}