This commit is contained in:
Adrian Groh 2024-12-06 11:38:56 +01:00
parent 04baa349a5
commit e364d411c8
Signed by: Gobidev
GPG Key ID: 3AA3153E98B0D771
3 changed files with 259 additions and 0 deletions

61
day6/Cargo.lock generated Normal file
View File

@ -0,0 +1,61 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 4
[[package]]
name = "crossbeam-deque"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
dependencies = [
"crossbeam-epoch",
"crossbeam-utils",
]
[[package]]
name = "crossbeam-epoch"
version = "0.9.18"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
dependencies = [
"crossbeam-utils",
]
[[package]]
name = "crossbeam-utils"
version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "day6"
version = "0.1.0"
dependencies = [
"rayon",
]
[[package]]
name = "either"
version = "1.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0"
[[package]]
name = "rayon"
version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [
"either",
"rayon-core",
]
[[package]]
name = "rayon-core"
version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [
"crossbeam-deque",
"crossbeam-utils",
]

7
day6/Cargo.toml Normal file
View File

@ -0,0 +1,7 @@
[package]
name = "day6"
version = "0.1.0"
edition = "2021"
[dependencies]
rayon = "1.10.0"

191
day6/src/main.rs Normal file
View File

@ -0,0 +1,191 @@
use rayon::prelude::*;
use std::fmt::Display;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum Direction {
Up,
Down,
Left,
Right,
}
use Direction::*;
impl Direction {
fn to_pos(self) -> (isize, isize) {
match self {
Up => (-1, 0),
Down => (1, 0),
Left => (0, -1),
Right => (0, 1),
}
}
fn turn(&mut self) {
match self {
Up => *self = Right,
Down => *self = Left,
Left => *self = Up,
Right => *self = Down,
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
enum PositionType {
Empty,
Visited(Vec<Direction>),
Obstructed,
}
use PositionType::*;
impl Display for PositionType {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Empty => write!(f, "."),
Visited(_) => write!(f, "X"),
Obstructed => write!(f, "#"),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct Guard {
position: (usize, usize),
direction: Direction,
}
#[derive(Debug, Clone, PartialEq, Eq)]
struct State {
map: Vec<Vec<PositionType>>,
guard: Guard,
}
impl Display for State {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
self.map
.iter()
.map(|l| l.iter().map(|c| c.to_string()).collect::<String>() + "\n")
.collect::<String>()
)
}
}
fn parse(input: &str) -> State {
let mut guard_pos = (0, 0);
State {
map: input
.lines()
.enumerate()
.map(|(line_idx, line)| {
line.chars()
.enumerate()
.map(|(c_idx, c)| match c {
'#' => Obstructed,
'^' => {
guard_pos = (line_idx, c_idx);
Empty
}
_ => Empty,
})
.collect()
})
.collect(),
guard: Guard {
position: guard_pos,
direction: Up,
},
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum MoveResult {
EndedOutside,
EndedLoop,
Running,
}
use MoveResult::*;
fn move_guard(state: &mut State) -> MoveResult {
if let Visited(ref mut directions) =
state.map[state.guard.position.0][state.guard.position.1]
{
if directions.contains(&state.guard.direction) {
return EndedLoop;
}
directions.push(state.guard.direction);
} else {
state.map[state.guard.position.0][state.guard.position.1] =
Visited(vec![]);
}
let direction_pos = state.guard.direction.to_pos();
let pos_in_front = (
((state.guard.position.0 as isize) + direction_pos.0) as usize,
((state.guard.position.1 as isize) + direction_pos.1) as usize,
);
let Some(line) = state.map.get(pos_in_front.0) else {
return EndedOutside;
};
let Some(pos_type) = line.get(pos_in_front.1) else {
return EndedOutside;
};
match pos_type {
Obstructed => {
state.guard.direction.turn();
}
_ => {
state.guard.position = pos_in_front;
}
}
Running
}
fn part1(state: &mut State) -> usize {
while move_guard(state) == Running {}
state
.map
.iter()
.map(|l| l.iter().filter(|c| matches!(c, Visited(_))).count())
.sum()
}
fn part2(state: &State) -> usize {
let mut original_path = state.clone();
while move_guard(&mut original_path) == Running {}
let original_path_positions: Vec<(usize, usize)> = original_path
.map
.iter()
.enumerate()
.flat_map(|(l_idx, l)| {
l.iter()
.enumerate()
.filter(|(_, c)| matches!(c, Visited(_)))
.map(move |(idx, _)| (l_idx, idx))
})
.collect();
original_path_positions
.par_iter()
.filter(|pos| {
let mut new_start_state = state.clone();
new_start_state.map[pos.0][pos.1] = Obstructed;
loop {
match move_guard(&mut new_start_state) {
EndedOutside => {
return false;
}
EndedLoop => {
return true;
}
Running => (),
}
}
})
.count()
}
fn main() {
let input = parse(include_str!("../input.txt"));
println!("{}", part1(&mut input.clone()));
println!("{}", part2(&input));
}