mirror of
https://github.com/RussellChamp/advent-of-code-2024-rust.git
synced 2026-10-27 23:52:29 +00:00
day 6 pt2
This commit is contained in:
1 parent
54591fadd8
commit
09038351d4
4 files changed
+125
-5
No files matched your search
@@ -134,7 +134,6 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_part_two() {
|
||||
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
|
||||
assert_eq!(result, Some(123));
|
||||
|
||||
+123
-3
@@ -1,7 +1,15 @@
|
||||
use std::collections::HashSet;
|
||||
use itertools::Itertools;
|
||||
|
||||
advent_of_code::solution!(6);
|
||||
|
||||
#[derive(PartialEq, Clone)]
|
||||
enum Tile {
|
||||
Empty,
|
||||
Object,
|
||||
Guard
|
||||
}
|
||||
|
||||
pub fn part_one(input: &str) -> Option<u32> {
|
||||
let mut pos = (0_isize, 0_isize);
|
||||
let mut dir = (-1_isize, 0_isize);
|
||||
@@ -51,14 +59,127 @@ pub fn part_one(input: &str) -> Option<u32> {
|
||||
Some(count_spaces(visited) as u32)
|
||||
}
|
||||
|
||||
pub fn part_two(_input: &str) -> Option<u32> {
|
||||
None
|
||||
pub fn part_two(input: &str) -> Option<u32> {
|
||||
let grid = input.lines().map(|line| line.chars().map(|c| {
|
||||
match c {
|
||||
'.' => Tile::Empty,
|
||||
'#' => Tile::Object,
|
||||
'^' => Tile::Guard,
|
||||
_ => panic!()
|
||||
}
|
||||
}).collect_vec()).collect_vec();
|
||||
|
||||
let mut looper_count = 0;
|
||||
// find all the spots the guard normally follows
|
||||
// then see if placing an object on one of those spots creates a loop
|
||||
|
||||
let paths = walk_path(&grid);
|
||||
// println!("CHECKING {:?} PATHS", paths.len());
|
||||
|
||||
for (row_idx, col_idx) in paths {
|
||||
if grid[row_idx][col_idx] != Tile::Empty { continue }
|
||||
let mut test_grid = grid.clone();
|
||||
test_grid[row_idx][col_idx] = Tile::Object; // Add a wall and check if it creates a loop
|
||||
|
||||
if does_loop(&test_grid) {
|
||||
looper_count += 1;
|
||||
// print!("!");
|
||||
// let _ = io::stdout().flush();
|
||||
} else {
|
||||
// print!("x");
|
||||
// let _ = io::stdout().flush();
|
||||
}
|
||||
}
|
||||
|
||||
Some(looper_count)
|
||||
}
|
||||
|
||||
fn count_spaces(grid: Vec<Vec<i32>>) -> usize {
|
||||
grid.iter().flat_map(|line: &Vec<_>| line.iter().filter(|v| v > &&0)).count()
|
||||
}
|
||||
|
||||
fn walk_path(grid: &Vec<Vec<Tile>>) -> Vec<(usize, usize)> {
|
||||
let mut pos = grid.iter().enumerate().find_map(|(row_idx, row)| {
|
||||
row.iter().enumerate().find_map(|(col_idx, cell)| {
|
||||
if *cell == Tile::Guard { Some((row_idx as isize, col_idx as isize)) } else { None }
|
||||
})
|
||||
}).unwrap();
|
||||
let mut dir = (-1_isize, 0_isize);
|
||||
|
||||
let mut history = HashSet::new();
|
||||
history.insert((pos.0 as usize, pos.1 as usize));
|
||||
|
||||
let is_valid_position = |(row_idx, col_idx)| {
|
||||
(0..grid.len() as isize).contains(&row_idx) && (0..grid[0].len() as isize).contains(&col_idx)
|
||||
};
|
||||
|
||||
loop {
|
||||
let new_pos = (pos.0 + dir.0, pos.1 + dir.1);
|
||||
if !is_valid_position(new_pos) { break }
|
||||
|
||||
if grid[new_pos.0 as usize][new_pos.1 as usize] == Tile::Object {
|
||||
// if it is a blocker, turn 90deg
|
||||
let directions = [(-1, 0), (0, 1), (1, 0), (0, -1), (-1, 0)];
|
||||
let new_dir = *directions.iter().skip_while(|d| **d != dir).nth(1).unwrap();
|
||||
dir.0 = new_dir.0;
|
||||
dir.1 = new_dir.1;
|
||||
} else {
|
||||
// else move into the new position and mark it as entered
|
||||
history.insert((new_pos.0 as usize, new_pos.1 as usize));
|
||||
pos.0 = new_pos.0;
|
||||
pos.1 = new_pos.1;
|
||||
}
|
||||
}
|
||||
|
||||
history.into_iter().collect_vec()
|
||||
}
|
||||
|
||||
fn does_loop(grid: &Vec<Vec<Tile>>) -> bool {
|
||||
let mut pos = grid.iter().enumerate().find_map(|(row_idx, row)| {
|
||||
row.iter().enumerate().find_map(|(col_idx, cell)| {
|
||||
if *cell == Tile::Guard { Some((row_idx as isize, col_idx as isize)) } else { None }
|
||||
})
|
||||
}).unwrap();
|
||||
let mut dir = (-1_isize, 0_isize);
|
||||
|
||||
let mut history = vec![];
|
||||
history.push(((pos.0, pos.1), (-1_isize, 0_isize)));
|
||||
|
||||
|
||||
let is_valid_position = |(row_idx, col_idx)| {
|
||||
(0..grid.len() as isize).contains(&row_idx) && (0..grid[0].len() as isize).contains(&col_idx)
|
||||
};
|
||||
|
||||
loop {
|
||||
let new_pos = (pos.0 + dir.0, pos.1 + dir.1);
|
||||
if !is_valid_position(new_pos) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if grid[new_pos.0 as usize][new_pos.1 as usize] == Tile::Object {
|
||||
// if it is a blocker, turn 90deg
|
||||
let directions = [(-1, 0), (0, 1), (1, 0), (0, -1), (-1, 0)];
|
||||
let new_dir = *directions.iter().skip_while(|d| **d != dir).nth(1).unwrap();
|
||||
|
||||
if history.contains(&(pos, new_dir)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
dir.0 = new_dir.0;
|
||||
dir.1 = new_dir.1;
|
||||
} else {
|
||||
// else move into the new position and mark it as entered
|
||||
if history.contains(&((new_pos.0, new_pos.1), dir)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
history.push(((new_pos.0, new_pos.1), dir));
|
||||
pos.0 = new_pos.0;
|
||||
pos.1 = new_pos.1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -81,7 +202,6 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_part_two() {
|
||||
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
|
||||
assert_eq!(result, Some(6));
|
||||
|
||||
@@ -124,6 +124,7 @@ mod tests {
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[ignore]
|
||||
fn test_part_two() {
|
||||
let result = part_two(&advent_of_code::template::read_file("examples", DAY));
|
||||
assert_eq!(result, Some(3440247820));
|
||||
|
||||
+1
-1
@@ -124,7 +124,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_part_one_2() {
|
||||
let result = part_one(&advent_of_code::template::read_file("examples", DAY));
|
||||
let result = part_one(&advent_of_code::template::read_file_part("examples", DAY, 2));
|
||||
assert_eq!(result, Some(11048));
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user