feat(day6): init
This commit is contained in:
parent
6394c75524
commit
8ee1f29eed
2 changed files with 167 additions and 0 deletions
165
src/solutions/day_06.rs
Normal file
165
src/solutions/day_06.rs
Normal file
|
@ -0,0 +1,165 @@
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
use crate::common::{Answer, Solution};
|
||||||
|
|
||||||
|
pub struct Day06;
|
||||||
|
|
||||||
|
impl Solution for Day06 {
|
||||||
|
fn name(&self) -> &'static str {
|
||||||
|
"Guard Gallivant"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_a(&self, input: &str) -> Answer {
|
||||||
|
let grid = input
|
||||||
|
.lines()
|
||||||
|
.map(|l| l.chars().collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let guard_pos = input
|
||||||
|
.lines()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(x, l)| l.find('^').map(|y| (x, y)))
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let guard = Guard {
|
||||||
|
coords: guard_pos,
|
||||||
|
direction: Direction::Up,
|
||||||
|
};
|
||||||
|
|
||||||
|
Answer::Number(get_positions(&grid, guard).len() as u64)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn part_b(&self, input: &str) -> Answer {
|
||||||
|
let grid = input
|
||||||
|
.lines()
|
||||||
|
.map(|l| l.chars().collect::<Vec<_>>())
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
|
||||||
|
let guard_pos = input
|
||||||
|
.lines()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(|(x, l)| l.find('^').map(|y| (x, y)))
|
||||||
|
.next()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let guard = Guard {
|
||||||
|
coords: guard_pos,
|
||||||
|
direction: Direction::Up,
|
||||||
|
};
|
||||||
|
|
||||||
|
let count = get_positions(&grid, guard)
|
||||||
|
.iter()
|
||||||
|
.filter(|&&coords| {
|
||||||
|
let tmp_guard = Guard {
|
||||||
|
coords: guard_pos,
|
||||||
|
direction: Direction::Up,
|
||||||
|
};
|
||||||
|
|
||||||
|
is_infinite_loop(&grid, tmp_guard, coords)
|
||||||
|
})
|
||||||
|
.count();
|
||||||
|
|
||||||
|
Answer::Number(count as u64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_positions(grid: &[Vec<char>], mut guard: Guard) -> HashSet<(usize, usize)> {
|
||||||
|
let max_coords = (grid.len() - 1, grid[0].len() - 1);
|
||||||
|
let mut positions = HashSet::new();
|
||||||
|
|
||||||
|
while let Some(next) = guard.next_coords(&max_coords) {
|
||||||
|
if grid[next.0][next.1] == '#' {
|
||||||
|
guard.turn_right();
|
||||||
|
} else {
|
||||||
|
positions.insert(next);
|
||||||
|
guard.coords = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
positions
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_infinite_loop(grid: &[Vec<char>], mut guard: Guard, block_coords: (usize, usize)) -> bool {
|
||||||
|
let max_coords = (grid.len() - 1, grid[0].len() - 1);
|
||||||
|
let mut positions = HashSet::new();
|
||||||
|
|
||||||
|
while let Some(next) = guard.next_coords(&max_coords) {
|
||||||
|
if positions.contains(&guard) {
|
||||||
|
return true;
|
||||||
|
} else if grid[next.0][next.1] == '#' || next == block_coords {
|
||||||
|
guard.turn_right();
|
||||||
|
} else {
|
||||||
|
positions.insert(guard);
|
||||||
|
guard.coords = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
enum Direction {
|
||||||
|
Up,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
Right,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(PartialEq, Eq, Hash, Clone, Copy)]
|
||||||
|
struct Guard {
|
||||||
|
coords: (usize, usize),
|
||||||
|
direction: Direction,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Guard {
|
||||||
|
fn turn_right(&mut self) {
|
||||||
|
self.direction = match self.direction {
|
||||||
|
Direction::Up => Direction::Right,
|
||||||
|
Direction::Down => Direction::Left,
|
||||||
|
Direction::Left => Direction::Up,
|
||||||
|
Direction::Right => Direction::Down,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Assumes (0,0) is top left, .0 is the line and .1 the column.
|
||||||
|
fn next_coords(&self, max: &(usize, usize)) -> Option<(usize, usize)> {
|
||||||
|
match self.direction {
|
||||||
|
Direction::Up => self.coords.0.checked_sub(1).map(|n| (n, self.coords.1)),
|
||||||
|
Direction::Down => (self.coords.0 < max.0).then(|| (self.coords.0 + 1, self.coords.1)),
|
||||||
|
Direction::Left => self.coords.1.checked_sub(1).map(|n| (self.coords.0, n)),
|
||||||
|
Direction::Right => (self.coords.1 < max.1).then(|| (self.coords.0, self.coords.1 + 1)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use super::Day06;
|
||||||
|
use crate::common::Solution;
|
||||||
|
|
||||||
|
use indoc::indoc;
|
||||||
|
|
||||||
|
const INPUT: &str = indoc! {"
|
||||||
|
....#.....
|
||||||
|
.........#
|
||||||
|
..........
|
||||||
|
..#.......
|
||||||
|
.......#..
|
||||||
|
..........
|
||||||
|
.#..^.....
|
||||||
|
........#.
|
||||||
|
#.........
|
||||||
|
......#...
|
||||||
|
"};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part_a() {
|
||||||
|
assert_eq!(Day06.part_a(INPUT), 41.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part_b() {
|
||||||
|
assert_eq!(Day06.part_b(INPUT), 6.into());
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ mod day_02;
|
||||||
mod day_03;
|
mod day_03;
|
||||||
mod day_04;
|
mod day_04;
|
||||||
mod day_05;
|
mod day_05;
|
||||||
|
mod day_06;
|
||||||
|
|
||||||
pub const SOLUTIONS: &[&dyn Solution] = &[
|
pub const SOLUTIONS: &[&dyn Solution] = &[
|
||||||
&day_01::Day01,
|
&day_01::Day01,
|
||||||
|
@ -12,4 +13,5 @@ pub const SOLUTIONS: &[&dyn Solution] = &[
|
||||||
&day_03::Day03,
|
&day_03::Day03,
|
||||||
&day_04::Day04,
|
&day_04::Day04,
|
||||||
&day_05::Day05,
|
&day_05::Day05,
|
||||||
|
&day_06::Day06,
|
||||||
];
|
];
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue