Compare commits

..

No commits in common. "4b85a906353d6d3c1f36abf874f09c662d29ff57" and "6283ff37f920c56af6207f7e1a9b23bdbe9edc06" have entirely different histories.

4 changed files with 16 additions and 73 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

@ -1,6 +1,6 @@
<!-- AOC TILES BEGIN --> <!-- AOC TILES BEGIN -->
<h1 align="center"> <h1 align="center">
2024 - 32 ⭐ - Rust 2024 - 31 ⭐ - Rust
</h1> </h1>
<a href="src/day1.rs"> <a href="src/day1.rs">
<img src=".aoc_tiles/tiles/2024/01.png" width="161px"> <img src=".aoc_tiles/tiles/2024/01.png" width="161px">

View File

@ -1,11 +1,8 @@
use aoc_runner_derive::aoc; use aoc_runner_derive::{aoc, aoc_generator};
use grid::{AsCoord2d, Coord2d, Grid}; use grid::{AsCoord2d, Coord2d, Grid};
use itertools::Itertools;
use std::{ use std::{
collections::{BinaryHeap, HashMap}, collections::{BinaryHeap, HashMap},
i64,
str::FromStr, str::FromStr,
usize,
}; };
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)] #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)]
@ -26,7 +23,7 @@ impl FacingDirection {
} }
} }
fn reachable(&self) -> [FacingDirection; 3] { fn reachable(&self) -> [FacingDirection; 3] {
// Can move perpendicularly or the same direction, backwards would always increase path cost // Can move perpendicularly or the same direction, not backwards
match self { match self {
FacingDirection::East | FacingDirection::West => [*self, FacingDirection::North, FacingDirection::South], FacingDirection::East | FacingDirection::West => [*self, FacingDirection::North, FacingDirection::South],
FacingDirection::South | FacingDirection::North => [*self, FacingDirection::East, FacingDirection::West], FacingDirection::South | FacingDirection::North => [*self, FacingDirection::East, FacingDirection::West],
@ -39,7 +36,6 @@ struct State {
cost: usize, cost: usize,
position: Coord2d, position: Coord2d,
facing: FacingDirection, facing: FacingDirection,
path: Vec<Coord2d>,
} }
impl Ord for State { impl Ord for State {
@ -60,60 +56,35 @@ impl PartialOrd for State {
struct Maze { struct Maze {
map: Grid<u8>, map: Grid<u8>,
paths: HashMap<usize, Vec<Vec<Coord2d>>>,
} }
impl FromStr for Maze { impl FromStr for Maze {
type Err = Box<dyn std::error::Error>; type Err = Box<dyn std::error::Error>;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let map: Grid<u8> = s.parse()?; let map: Grid<u8> = s.parse()?;
let paths = HashMap::new();
Ok(Self { map, paths }) Ok(Self { map })
} }
} }
impl Maze { impl Maze {
fn dijkstra<const RECORD_PATHS: bool>(&mut self) -> usize { fn dijkstra(&mut self) -> usize {
let start = self.map.find(&b'S').expect("can't find start").to_coord(); let start = self.map.find(&b'S').expect("can't find start").to_coord();
let finish = self.map.find(&b'E').expect("can't find finish").to_coord(); let finish = self.map.find(&b'E').expect("can't find finish").to_coord();
let mut distances = HashMap::new(); let mut distances = HashMap::new();
let mut queue = BinaryHeap::with_capacity(self.map.data.len()); let mut queue = BinaryHeap::with_capacity(self.map.data.len());
let mut best_cost = usize::MAX;
distances.insert((start, FacingDirection::East), 0); distances.insert((start, FacingDirection::East), 0);
queue.push(State { queue.push(State {
cost: 0, cost: 0,
position: start, position: start,
facing: FacingDirection::East, facing: FacingDirection::East,
path: Vec::new(),
}); });
while let Some(State { while let Some(State { cost, position, facing }) = queue.pop() {
cost,
position,
facing,
path,
}) = queue.pop()
{
let mut new_path = path.clone();
new_path.push(position);
if position == finish { if position == finish {
if RECORD_PATHS { return cost;
if cost < best_cost {
best_cost = cost
}
if !self.paths.contains_key(&cost) {
self.paths.insert(cost, vec![new_path.clone()]);
} else {
self.paths.get_mut(&cost).unwrap().push(new_path.clone());
}
continue;
} else {
return cost;
}
} }
if distances.get(&(position, facing)).is_some_and(|v| cost > *v) { if distances.get(&(position, facing)).is_some_and(|v| cost > *v) {
@ -129,23 +100,18 @@ impl Maze {
{ {
if distances if distances
.get(&(new_position, *new_dir)) .get(&(new_position, *new_dir))
.is_none_or(|best_cost| new_cost <= *best_cost) .is_none_or(|best_cost| new_cost < *best_cost)
{ {
queue.push(State { queue.push(State {
cost: new_cost, cost: new_cost,
position: new_position, position: new_position,
facing: *new_dir, facing: *new_dir,
path: new_path.clone(),
}); });
distances.insert((new_position, *new_dir), new_cost); distances.insert((new_position, *new_dir), new_cost);
} }
} }
} }
if best_cost == usize::MAX || !RECORD_PATHS { panic!("no path found");
panic!("no path found");
} else {
return best_cost;
}
} }
} }
@ -156,21 +122,12 @@ fn parse(input: &str) -> Maze {
#[aoc(day16, part1)] #[aoc(day16, part1)]
pub fn part1(input: &str) -> usize { pub fn part1(input: &str) -> usize {
let mut maze = parse(input); let mut maze = parse(input);
maze.dijkstra::<false>() maze.dijkstra()
} }
#[aoc(day16, part2)] #[aoc(day16, part2)]
pub fn part2(input: &str) -> usize { pub fn part2(input: &str) -> i64 {
let mut maze = parse(input); todo!()
let best_cost = maze.dijkstra::<true>();
let best_paths = maze.paths.get(&best_cost).unwrap();
let best_path_tiles = best_paths.into_iter().flatten().collect_vec();
let mut path_map = maze.map.clone();
for tile in best_path_tiles {
path_map.set(&tile, b'O');
}
path_map.count(&b'O')
} }
#[cfg(test)] #[cfg(test)]
@ -211,22 +168,14 @@ mod tests {
#################"; #################";
#[test] #[test]
fn part1_example1() { fn part1_example() {
assert_eq!(part1(EXAMPLE1), 7036); assert_eq!(part1(EXAMPLE1), 7036);
}
#[test]
fn part1_example2() {
assert_eq!(part1(EXAMPLE2), 11048); assert_eq!(part1(EXAMPLE2), 11048);
} }
#[test] #[test]
fn part2_example1() { fn part2_example() {
assert_eq!(part2(EXAMPLE1), 45); assert_eq!(part2(EXAMPLE1), 0);
} assert_eq!(part2(EXAMPLE2), 0);
#[test]
fn part2_example2() {
assert_eq!(part2(EXAMPLE2), 64);
} }
} }

View File

@ -181,12 +181,6 @@ impl<T: Clone + Eq + PartialEq + Debug> Grid<T> {
None => None, None => None,
} }
} }
pub fn get_mut<C: AsCoord2d>(&mut self, c: &C) -> Option<&mut T> {
match self.valid_pos(c) {
Some(pos) => Some(self.data.get_mut(pos).unwrap()),
None => None,
}
}
pub fn set<C: AsCoord2d>(&mut self, c: &C, mut val: T) -> Option<T> { pub fn set<C: AsCoord2d>(&mut self, c: &C, mut val: T) -> Option<T> {
match self.valid_pos(c) { match self.valid_pos(c) {
Some(pos) => { Some(pos) => {