Add day6
This commit is contained in:
parent
04baa349a5
commit
e364d411c8
61
day6/Cargo.lock
generated
Normal file
61
day6/Cargo.lock
generated
Normal 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
7
day6/Cargo.toml
Normal 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
191
day6/src/main.rs
Normal 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));
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user