This commit is contained in:
parent
f2186d18d3
commit
6283ff37f9
Binary file not shown.
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 7.2 KiB |
@ -1,6 +1,6 @@
|
|||||||
<!-- AOC TILES BEGIN -->
|
<!-- AOC TILES BEGIN -->
|
||||||
<h1 align="center">
|
<h1 align="center">
|
||||||
2024 - 30 ⭐ - 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">
|
||||||
@ -47,4 +47,7 @@
|
|||||||
<a href="src/day15.rs">
|
<a href="src/day15.rs">
|
||||||
<img src=".aoc_tiles/tiles/2024/15.png" width="161px">
|
<img src=".aoc_tiles/tiles/2024/15.png" width="161px">
|
||||||
</a>
|
</a>
|
||||||
|
<a href="src/day16.rs">
|
||||||
|
<img src=".aoc_tiles/tiles/2024/16.png" width="161px">
|
||||||
|
</a>
|
||||||
<!-- AOC TILES END -->
|
<!-- AOC TILES END -->
|
||||||
|
181
src/day16.rs
Normal file
181
src/day16.rs
Normal file
@ -0,0 +1,181 @@
|
|||||||
|
use aoc_runner_derive::{aoc, aoc_generator};
|
||||||
|
use grid::{AsCoord2d, Coord2d, Grid};
|
||||||
|
use std::{
|
||||||
|
collections::{BinaryHeap, HashMap},
|
||||||
|
str::FromStr,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug, Ord, PartialOrd)]
|
||||||
|
enum FacingDirection {
|
||||||
|
East,
|
||||||
|
South,
|
||||||
|
West,
|
||||||
|
North,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FacingDirection {
|
||||||
|
fn ofs(&self) -> (i64, i64) {
|
||||||
|
match self {
|
||||||
|
FacingDirection::East => (1, 0),
|
||||||
|
FacingDirection::South => (0, 1),
|
||||||
|
FacingDirection::West => (-1, 0),
|
||||||
|
FacingDirection::North => (0, -1),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn reachable(&self) -> [FacingDirection; 3] {
|
||||||
|
// Can move perpendicularly or the same direction, not backwards
|
||||||
|
match self {
|
||||||
|
FacingDirection::East | FacingDirection::West => [*self, FacingDirection::North, FacingDirection::South],
|
||||||
|
FacingDirection::South | FacingDirection::North => [*self, FacingDirection::East, FacingDirection::West],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Eq, PartialEq, Debug)]
|
||||||
|
struct State {
|
||||||
|
cost: usize,
|
||||||
|
position: Coord2d,
|
||||||
|
facing: FacingDirection,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for State {
|
||||||
|
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||||
|
other
|
||||||
|
.cost
|
||||||
|
.cmp(&self.cost)
|
||||||
|
.then_with(|| self.position.cmp(&other.position))
|
||||||
|
.then_with(|| self.facing.cmp(&other.facing))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for State {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Maze {
|
||||||
|
map: Grid<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromStr for Maze {
|
||||||
|
type Err = Box<dyn std::error::Error>;
|
||||||
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||||
|
let map: Grid<u8> = s.parse()?;
|
||||||
|
|
||||||
|
Ok(Self { map })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Maze {
|
||||||
|
fn dijkstra(&mut self) -> usize {
|
||||||
|
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 mut distances = HashMap::new();
|
||||||
|
let mut queue = BinaryHeap::with_capacity(self.map.data.len());
|
||||||
|
|
||||||
|
distances.insert((start, FacingDirection::East), 0);
|
||||||
|
queue.push(State {
|
||||||
|
cost: 0,
|
||||||
|
position: start,
|
||||||
|
facing: FacingDirection::East,
|
||||||
|
});
|
||||||
|
|
||||||
|
while let Some(State { cost, position, facing }) = queue.pop() {
|
||||||
|
if position == finish {
|
||||||
|
return cost;
|
||||||
|
}
|
||||||
|
|
||||||
|
if distances.get(&(position, facing)).is_some_and(|v| cost > *v) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (new_dir, new_position, new_cost) in facing
|
||||||
|
.reachable()
|
||||||
|
.iter()
|
||||||
|
.map(|dir| (dir, &position + dir.ofs()))
|
||||||
|
.filter(|(_, pos)| self.map.get(pos).is_some_and(|c| *c != b'#'))
|
||||||
|
.map(|(dir, pos)| (dir, pos, if *dir == facing { cost + 1 } else { cost + 1001 }))
|
||||||
|
{
|
||||||
|
if distances
|
||||||
|
.get(&(new_position, *new_dir))
|
||||||
|
.is_none_or(|best_cost| new_cost < *best_cost)
|
||||||
|
{
|
||||||
|
queue.push(State {
|
||||||
|
cost: new_cost,
|
||||||
|
position: new_position,
|
||||||
|
facing: *new_dir,
|
||||||
|
});
|
||||||
|
distances.insert((new_position, *new_dir), new_cost);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic!("no path found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse(input: &str) -> Maze {
|
||||||
|
input.parse().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day16, part1)]
|
||||||
|
pub fn part1(input: &str) -> usize {
|
||||||
|
let mut maze = parse(input);
|
||||||
|
maze.dijkstra()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[aoc(day16, part2)]
|
||||||
|
pub fn part2(input: &str) -> i64 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
const EXAMPLE1: &str = "###############
|
||||||
|
#.......#....E#
|
||||||
|
#.#.###.#.###.#
|
||||||
|
#.....#.#...#.#
|
||||||
|
#.###.#####.#.#
|
||||||
|
#.#.#.......#.#
|
||||||
|
#.#.#####.###.#
|
||||||
|
#...........#.#
|
||||||
|
###.#.#####.#.#
|
||||||
|
#...#.....#.#.#
|
||||||
|
#.#.#.###.#.#.#
|
||||||
|
#.....#...#.#.#
|
||||||
|
#.###.#.#.#.#.#
|
||||||
|
#S..#.....#...#
|
||||||
|
###############";
|
||||||
|
|
||||||
|
const EXAMPLE2: &str = "#################
|
||||||
|
#...#...#...#..E#
|
||||||
|
#.#.#.#.#.#.#.#.#
|
||||||
|
#.#.#.#...#...#.#
|
||||||
|
#.#.#.#.###.#.#.#
|
||||||
|
#...#.#.#.....#.#
|
||||||
|
#.#.#.#.#.#####.#
|
||||||
|
#.#...#.#.#.....#
|
||||||
|
#.#.#####.#.###.#
|
||||||
|
#.#.#.......#...#
|
||||||
|
#.#.###.#####.###
|
||||||
|
#.#.#...#.....#.#
|
||||||
|
#.#.#.#####.###.#
|
||||||
|
#.#.#.........#.#
|
||||||
|
#.#.#.#########.#
|
||||||
|
#S#.............#
|
||||||
|
#################";
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part1_example() {
|
||||||
|
assert_eq!(part1(EXAMPLE1), 7036);
|
||||||
|
assert_eq!(part1(EXAMPLE2), 11048);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn part2_example() {
|
||||||
|
assert_eq!(part2(EXAMPLE1), 0);
|
||||||
|
assert_eq!(part2(EXAMPLE2), 0);
|
||||||
|
}
|
||||||
|
}
|
@ -1,3 +1,4 @@
|
|||||||
|
mod day16;
|
||||||
use aoc_runner_derive::aoc_lib;
|
use aoc_runner_derive::aoc_lib;
|
||||||
|
|
||||||
pub mod day1;
|
pub mod day1;
|
||||||
|
@ -7,7 +7,7 @@ use std::{
|
|||||||
str::FromStr,
|
str::FromStr,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
|
||||||
pub struct Coord2d {
|
pub struct Coord2d {
|
||||||
pub x: i64,
|
pub x: i64,
|
||||||
pub y: i64,
|
pub y: i64,
|
||||||
@ -126,7 +126,7 @@ pub struct Grid<T> {
|
|||||||
width: i64,
|
width: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Clone + Eq + PartialEq + Display + Debug> Grid<T> {
|
impl<T: Clone + Eq + PartialEq + Debug> Grid<T> {
|
||||||
pub fn new(width: i64) -> Self {
|
pub fn new(width: i64) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data: Vec::new(),
|
data: Vec::new(),
|
||||||
@ -134,7 +134,7 @@ impl<T: Clone + Eq + PartialEq + Display + Debug> Grid<T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
/// Returns a new [Grid] with the same shape (width x height) as `self`, filled with `fill`
|
/// Returns a new [Grid] with the same shape (width x height) as `self`, filled with `fill`
|
||||||
pub fn same_shape<NT: Clone + Eq + PartialEq + Display + Debug>(&self, fill: NT) -> Grid<NT> {
|
pub fn same_shape<NT: Clone + Eq + PartialEq + Debug>(&self, fill: NT) -> Grid<NT> {
|
||||||
Grid {
|
Grid {
|
||||||
data: Vec::from_iter(repeat(fill).take(self.width() * self.height())),
|
data: Vec::from_iter(repeat(fill).take(self.width() * self.height())),
|
||||||
width: self.width,
|
width: self.width,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user