Solved day 6
This commit is contained in:
119
src/day6.rs
119
src/day6.rs
@@ -1,11 +1,13 @@
|
|||||||
use std::collections::HashSet;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use crate::day_solver::DaySolver;
|
use crate::day_solver::DaySolver;
|
||||||
use crate::util::{Coord, Grid};
|
use crate::util::{Coord, Grid};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use crate::util::read_file;
|
use crate::util::read_file;
|
||||||
|
|
||||||
pub struct Day6 {
|
pub struct Day6 {
|
||||||
maze: Grid<char>
|
maze: Grid<char>,
|
||||||
|
initial_path: Option<Vec<Coord<usize>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
const DIRECTIONS: [Coord<isize>; 4] = [
|
const DIRECTIONS: [Coord<isize>; 4] = [
|
||||||
@@ -15,6 +17,12 @@ const DIRECTIONS: [Coord<isize>; 4] = [
|
|||||||
Coord { x: -1, y: 0 }
|
Coord { x: -1, y: 0 }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
enum GuardResult {
|
||||||
|
Loop,
|
||||||
|
Walkout(Vec<Coord<usize>>),
|
||||||
|
Illegal
|
||||||
|
}
|
||||||
|
|
||||||
impl Day6 {
|
impl Day6 {
|
||||||
|
|
||||||
pub fn create(input: String) -> Self {
|
pub fn create(input: String) -> Self {
|
||||||
@@ -22,46 +30,101 @@ impl Day6 {
|
|||||||
|
|
||||||
// Put the input into the day struct
|
// Put the input into the day struct
|
||||||
Day6 {
|
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 {
|
impl DaySolver for Day6 {
|
||||||
|
|
||||||
|
|
||||||
fn solve_part1(&mut self) -> String {
|
fn solve_part1(&mut self) -> String {
|
||||||
let mut cur_pos = self.maze.find(&'^').unwrap();
|
if let GuardResult::Walkout(path) = Self::simulate_guard(&self.maze) {
|
||||||
let mut cur_direction_index = 0;
|
self.initial_path = Some(path.to_owned());
|
||||||
let mut cur_direction = DIRECTIONS[cur_direction_index];
|
path.iter().unique().count().to_string()
|
||||||
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 {
|
} else {
|
||||||
cur_pos = next_pos;
|
panic!("The guard got stuck in the maze")
|
||||||
visited_positions.insert(cur_pos);
|
|
||||||
next_pos = cur_pos.add_signed(cur_direction);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
visited_positions.len().to_string()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn solve_part2(&mut self) -> 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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user