feat: day 6
This commit is contained in:
parent
b24c359847
commit
506fec4365
56
Cargo.lock
generated
56
Cargo.lock
generated
|
@ -34,6 +34,7 @@ dependencies = [
|
||||||
"regex",
|
"regex",
|
||||||
"tracing",
|
"tracing",
|
||||||
"tracing-subscriber",
|
"tracing-subscriber",
|
||||||
|
"tracing-test",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -133,6 +134,15 @@ version = "0.4.22"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "matchers"
|
||||||
|
version = "0.1.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
|
||||||
|
dependencies = [
|
||||||
|
"regex-automata 0.1.10",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "memchr"
|
name = "memchr"
|
||||||
version = "2.7.4"
|
version = "2.7.4"
|
||||||
|
@ -217,8 +227,17 @@ checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-automata",
|
"regex-automata 0.4.9",
|
||||||
"regex-syntax",
|
"regex-syntax 0.8.5",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-automata"
|
||||||
|
version = "0.1.10"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
|
||||||
|
dependencies = [
|
||||||
|
"regex-syntax 0.6.29",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
@ -229,9 +248,15 @@ checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"aho-corasick",
|
"aho-corasick",
|
||||||
"memchr",
|
"memchr",
|
||||||
"regex-syntax",
|
"regex-syntax 0.8.5",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "regex-syntax"
|
||||||
|
version = "0.6.29"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "regex-syntax"
|
name = "regex-syntax"
|
||||||
version = "0.8.5"
|
version = "0.8.5"
|
||||||
|
@ -345,14 +370,39 @@ version = "0.3.19"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"matchers",
|
||||||
"nu-ansi-term",
|
"nu-ansi-term",
|
||||||
|
"once_cell",
|
||||||
|
"regex",
|
||||||
"sharded-slab",
|
"sharded-slab",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"thread_local",
|
"thread_local",
|
||||||
|
"tracing",
|
||||||
"tracing-core",
|
"tracing-core",
|
||||||
"tracing-log",
|
"tracing-log",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-test"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "557b891436fe0d5e0e363427fc7f217abf9ccd510d5136549847bdcbcd011d68"
|
||||||
|
dependencies = [
|
||||||
|
"tracing-core",
|
||||||
|
"tracing-subscriber",
|
||||||
|
"tracing-test-macro",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "tracing-test-macro"
|
||||||
|
version = "0.2.5"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "04659ddb06c87d233c566112c1c9c5b9e98256d9af50ec3bc9c8327f873a7568"
|
||||||
|
dependencies = [
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "unicode-ident"
|
name = "unicode-ident"
|
||||||
version = "1.0.14"
|
version = "1.0.14"
|
||||||
|
|
|
@ -11,3 +11,4 @@ color-eyre = "0.6.3"
|
||||||
regex = "1.11.1"
|
regex = "1.11.1"
|
||||||
tracing = "0.1.41"
|
tracing = "0.1.41"
|
||||||
tracing-subscriber = "0.3.19"
|
tracing-subscriber = "0.3.19"
|
||||||
|
tracing-test = "0.2.5"
|
||||||
|
|
10
inputs/day06/example.txt
Normal file
10
inputs/day06/example.txt
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
....#.....
|
||||||
|
.........#
|
||||||
|
..........
|
||||||
|
..#.......
|
||||||
|
.......#..
|
||||||
|
..........
|
||||||
|
.#..^.....
|
||||||
|
........#.
|
||||||
|
#.........
|
||||||
|
......#...
|
216
src/day06.rs
Normal file
216
src/day06.rs
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
use std::collections::HashSet;
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
|
||||||
|
enum Direction {
|
||||||
|
Up,
|
||||||
|
Right,
|
||||||
|
Down,
|
||||||
|
Left,
|
||||||
|
}
|
||||||
|
impl Direction {
|
||||||
|
fn next(self) -> Self {
|
||||||
|
match self {
|
||||||
|
Direction::Up => Direction::Right,
|
||||||
|
Direction::Right => Direction::Down,
|
||||||
|
Direction::Down => Direction::Left,
|
||||||
|
Direction::Left => Direction::Up,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
|
||||||
|
enum Field {
|
||||||
|
Empty,
|
||||||
|
Blocked,
|
||||||
|
Guard(Direction),
|
||||||
|
}
|
||||||
|
fn parse_field(c: char) -> Field {
|
||||||
|
match c {
|
||||||
|
'.' => Field::Empty,
|
||||||
|
'^' => Field::Guard(Direction::Up),
|
||||||
|
'>' => Field::Guard(Direction::Right),
|
||||||
|
'v' => Field::Guard(Direction::Down),
|
||||||
|
'<' => Field::Guard(Direction::Left),
|
||||||
|
'#' => Field::Blocked,
|
||||||
|
c => panic!("Unknown field: {c}"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pt1(input: &str) -> usize {
|
||||||
|
let mut visited_fields: HashSet<(usize, usize)> = HashSet::new();
|
||||||
|
let mut current_pos = (0, 0);
|
||||||
|
let mut current_direction = Direction::Up;
|
||||||
|
let grid: Vec<_> = parse_grid(input, &mut current_direction, &mut current_pos);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
tracing::debug!("{current_pos:?} [{current_direction:?}]");
|
||||||
|
let next_pos: (usize, usize) = match current_direction {
|
||||||
|
Direction::Up => {
|
||||||
|
if current_pos.1 == 0 {
|
||||||
|
visited_fields.insert(current_pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(current_pos.0, current_pos.1 - 1)
|
||||||
|
}
|
||||||
|
Direction::Right => {
|
||||||
|
if grid[current_pos.1].len() - 1 == current_pos.0 {
|
||||||
|
visited_fields.insert(current_pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(current_pos.0 + 1, current_pos.1)
|
||||||
|
}
|
||||||
|
Direction::Down => {
|
||||||
|
if grid.len() - 1 == current_pos.1 {
|
||||||
|
visited_fields.insert(current_pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(current_pos.0, current_pos.1 + 1)
|
||||||
|
}
|
||||||
|
Direction::Left => {
|
||||||
|
if current_pos.0 == 0 {
|
||||||
|
visited_fields.insert(current_pos);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(current_pos.0 - 1, current_pos.1)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match grid
|
||||||
|
.get(next_pos.1)
|
||||||
|
.and_then(|l| l.get(next_pos.0))
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
Field::Empty => {
|
||||||
|
visited_fields.insert(current_pos);
|
||||||
|
current_pos = next_pos;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Field::Blocked => {
|
||||||
|
current_direction = current_direction.next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
Field::Guard(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
visited_fields.len()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn pt2(input: &str) -> usize {
|
||||||
|
let mut initial_position = (0, 0);
|
||||||
|
let mut initial_direction = Direction::Up;
|
||||||
|
let original_grid: Vec<_> = parse_grid(input, &mut initial_direction, &mut initial_position);
|
||||||
|
|
||||||
|
let mut result = 0;
|
||||||
|
for (y, row) in original_grid.iter().enumerate() {
|
||||||
|
for (x, _) in row.iter().enumerate() {
|
||||||
|
if (x, y) == initial_position {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
let mut grid = original_grid.clone();
|
||||||
|
grid[y][x] = Field::Blocked;
|
||||||
|
let mut current_pos = initial_position;
|
||||||
|
let mut current_direction = initial_direction;
|
||||||
|
let mut visited_fields: HashSet<((usize, usize), Direction)> = HashSet::new();
|
||||||
|
let mut is_valid = true;
|
||||||
|
'current_attempt: loop {
|
||||||
|
tracing::debug!("{current_pos:?} [{current_direction:?}]");
|
||||||
|
if !visited_fields.insert((current_pos, current_direction)) {
|
||||||
|
is_valid = false;
|
||||||
|
break 'current_attempt;
|
||||||
|
}
|
||||||
|
let next_pos = match current_direction {
|
||||||
|
Direction::Up => {
|
||||||
|
if current_pos.1 == 0 {
|
||||||
|
break 'current_attempt;
|
||||||
|
}
|
||||||
|
(current_pos.0, current_pos.1 - 1)
|
||||||
|
}
|
||||||
|
Direction::Right => {
|
||||||
|
if grid[current_pos.1].len() - 1 == current_pos.0 {
|
||||||
|
break 'current_attempt;
|
||||||
|
}
|
||||||
|
(current_pos.0 + 1, current_pos.1)
|
||||||
|
}
|
||||||
|
Direction::Down => {
|
||||||
|
if grid.len() - 1 == current_pos.1 {
|
||||||
|
break 'current_attempt;
|
||||||
|
}
|
||||||
|
(current_pos.0, current_pos.1 + 1)
|
||||||
|
}
|
||||||
|
Direction::Left => {
|
||||||
|
if current_pos.0 == 0 {
|
||||||
|
break 'current_attempt;
|
||||||
|
}
|
||||||
|
(current_pos.0 - 1, current_pos.1)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
match grid
|
||||||
|
.get(next_pos.1)
|
||||||
|
.and_then(|l| l.get(next_pos.0))
|
||||||
|
.unwrap()
|
||||||
|
{
|
||||||
|
Field::Empty => {
|
||||||
|
current_pos = next_pos;
|
||||||
|
continue 'current_attempt;
|
||||||
|
}
|
||||||
|
Field::Blocked => {
|
||||||
|
current_direction = current_direction.next();
|
||||||
|
continue 'current_attempt;
|
||||||
|
}
|
||||||
|
Field::Guard(_) => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !is_valid {
|
||||||
|
result += 1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_grid(
|
||||||
|
input: &str,
|
||||||
|
initial_direction: &mut Direction,
|
||||||
|
initial_position: &mut (usize, usize),
|
||||||
|
) -> Vec<Vec<Field>> {
|
||||||
|
input
|
||||||
|
.lines()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(row_index, line)| {
|
||||||
|
line.chars()
|
||||||
|
.enumerate()
|
||||||
|
.map(|(x, c)| match parse_field(c) {
|
||||||
|
Field::Empty => Field::Empty,
|
||||||
|
Field::Blocked => Field::Blocked,
|
||||||
|
Field::Guard(direction) => {
|
||||||
|
*initial_direction = direction;
|
||||||
|
*initial_position = (x, row_index);
|
||||||
|
Field::Empty
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::fs::read_to_string;
|
||||||
|
|
||||||
|
use tracing_test::traced_test;
|
||||||
|
|
||||||
|
use super::{pt1, pt2};
|
||||||
|
|
||||||
|
#[traced_test]
|
||||||
|
#[test]
|
||||||
|
pub fn test_pt1() {
|
||||||
|
let input =
|
||||||
|
read_to_string("./inputs/day06/example.txt").expect("Missing example.txt for day06");
|
||||||
|
assert_eq!(pt1(&input), 41)
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
pub fn test_pt2() {
|
||||||
|
let input =
|
||||||
|
read_to_string("./inputs/day06/example.txt").expect("Missing example.txt for day06");
|
||||||
|
|
||||||
|
assert_eq!(pt2(&input), 6)
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,15 +5,17 @@ mod day02;
|
||||||
mod day03;
|
mod day03;
|
||||||
mod day04;
|
mod day04;
|
||||||
mod day05;
|
mod day05;
|
||||||
|
mod day06;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
color_eyre::install().unwrap();
|
color_eyre::install().unwrap();
|
||||||
tracing_subscriber::fmt::init();
|
tracing_subscriber::fmt().init();
|
||||||
solve_day(1, day01::pt1, day01::pt2);
|
solve_day(1, day01::pt1, day01::pt2);
|
||||||
solve_day(2, day02::pt1, day02::pt2);
|
solve_day(2, day02::pt1, day02::pt2);
|
||||||
solve_day(3, day03::pt1, day03::pt2);
|
solve_day(3, day03::pt1, day03::pt2);
|
||||||
solve_day(4, day04::pt1, day04::pt2);
|
solve_day(4, day04::pt1, day04::pt2);
|
||||||
solve_day(5, day05::pt1, day05::pt2);
|
solve_day(5, day05::pt1, day05::pt2);
|
||||||
|
solve_day(6, day06::pt1, day06::pt2);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn solve_day<Fa, Fb, Ta, Tb>(day: u8, part_a: Fa, part_b: Fb)
|
fn solve_day<Fa, Fb, Ta, Tb>(day: u8, part_a: Fa, part_b: Fb)
|
||||||
|
|
Loading…
Reference in a new issue