Skip to content

Commit

Permalink
AoC 2024 Day 16 - rust
Browse files Browse the repository at this point in the history
  • Loading branch information
pareronia committed Dec 17, 2024
1 parent 76c4601 commit 917caf5
Show file tree
Hide file tree
Showing 6 changed files with 243 additions and 12 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
| ---| --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- |
| python3 | [](src/main/python/AoC2024_01.py) | [](src/main/python/AoC2024_02.py) | [](src/main/python/AoC2024_03.py) | [](src/main/python/AoC2024_04.py) | [](src/main/python/AoC2024_05.py) | [](src/main/python/AoC2024_06.py) | [](src/main/python/AoC2024_07.py) | [](src/main/python/AoC2024_08.py) | [](src/main/python/AoC2024_09.py) | [](src/main/python/AoC2024_10.py) | [](src/main/python/AoC2024_11.py) | [](src/main/python/AoC2024_12.py) | [](src/main/python/AoC2024_13.py) | [](src/main/python/AoC2024_14.py) | [](src/main/python/AoC2024_15.py) | [](src/main/python/AoC2024_16.py) | | | | | | | | | |
| java | [](src/main/java/AoC2024_01.java) | [](src/main/java/AoC2024_02.java) | [](src/main/java/AoC2024_03.java) | [](src/main/java/AoC2024_04.java) | [](src/main/java/AoC2024_05.java) | [](src/main/java/AoC2024_06.java) | [](src/main/java/AoC2024_07.java) | [](src/main/java/AoC2024_08.java) | | [](src/main/java/AoC2024_10.java) | [](src/main/java/AoC2024_11.java) | [](src/main/java/AoC2024_12.java) | | [](src/main/java/AoC2024_14.java) | [](src/main/java/AoC2024_15.java) | | | | | | | | | | |
| rust | [](src/main/rust/AoC2024_01/src/main.rs) | [](src/main/rust/AoC2024_02/src/main.rs) | [](src/main/rust/AoC2024_03/src/main.rs) | [](src/main/rust/AoC2024_04/src/main.rs) | [](src/main/rust/AoC2024_05/src/main.rs) | [](src/main/rust/AoC2024_06/src/main.rs) | [](src/main/rust/AoC2024_07/src/main.rs) | [](src/main/rust/AoC2024_08/src/main.rs) | | [](src/main/rust/AoC2024_10/src/main.rs) | | | [](src/main/rust/AoC2024_13/src/main.rs) | [](src/main/rust/AoC2024_14/src/main.rs) | [](src/main/rust/AoC2024_15/src/main.rs) | | | | | | | | | | |
| rust | [](src/main/rust/AoC2024_01/src/main.rs) | [](src/main/rust/AoC2024_02/src/main.rs) | [](src/main/rust/AoC2024_03/src/main.rs) | [](src/main/rust/AoC2024_04/src/main.rs) | [](src/main/rust/AoC2024_05/src/main.rs) | [](src/main/rust/AoC2024_06/src/main.rs) | [](src/main/rust/AoC2024_07/src/main.rs) | [](src/main/rust/AoC2024_08/src/main.rs) | | [](src/main/rust/AoC2024_10/src/main.rs) | | | [](src/main/rust/AoC2024_13/src/main.rs) | [](src/main/rust/AoC2024_14/src/main.rs) | [](src/main/rust/AoC2024_15/src/main.rs) | [](src/main/rust/AoC2024_16/src/main.rs) | | | | | | | | | |
<!-- @END:ImplementationsTable:2024@ -->

## 2023
Expand Down
2 changes: 1 addition & 1 deletion src/main/rust/AoC2023_17/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ impl AoC2023_17 {
},
|r#move| r#move.cell == end,
adjacent,
|r#move| r#move.cost,
|_, r#move| r#move.cost,
) as u32
}
}
Expand Down
8 changes: 8 additions & 0 deletions src/main/rust/AoC2024_16/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "AoC2024_16"
version = "0.1.0"
edition = "2021"

[dependencies]
aoc = { path = "../aoc" }
itertools = "0.11"
141 changes: 141 additions & 0 deletions src/main/rust/AoC2024_16/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#![allow(non_snake_case)]

use aoc::geometry::{Direction, Turn};
use aoc::graph::AStar;
use aoc::grid::{Cell, CharGrid, Grid};
use aoc::Puzzle;
use itertools::Itertools;

#[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)]
struct State {
pos: Cell,
dir: Direction,
}

struct AoC2024_16;

impl AoC2024_16 {
fn adjacent(&self, grid: &CharGrid, state: State) -> Vec<State> {
let mut dirs = vec![state.dir];
[Turn::Right, Turn::Left]
.into_iter()
.map(|t| state.dir.turn(t))
.for_each(|d| dirs.push(d));
dirs.into_iter()
.map(|dir| State {
pos: state.pos.try_at(dir).unwrap(),
dir,
})
.filter(|state| grid.get(&state.pos) != '#')
.collect_vec()
}
}

impl aoc::Puzzle for AoC2024_16 {
type Input = CharGrid;
type Output1 = usize;
type Output2 = usize;

aoc::puzzle_year_day!(2024, 16);

fn parse_input(&self, lines: Vec<String>) -> Self::Input {
CharGrid::from(&lines.iter().map(AsRef::as_ref).collect::<Vec<_>>())
}

fn part_1(&self, grid: &Self::Input) -> Self::Output1 {
let start = Cell::at(grid.height() - 2, 1);
let end = Cell::at(1, grid.width() - 2);
AStar::distance(
State {
pos: start,
dir: Direction::Right,
},
|state| state.pos == end,
|state| self.adjacent(grid, state),
|curr, next| if curr.dir == next.dir { 1 } else { 1001 },
)
}

fn part_2(&self, grid: &Self::Input) -> Self::Output2 {
let start = Cell::at(grid.height() - 2, 1);
let end = Cell::at(1, grid.width() - 2);
let result = AStar::all(
State {
pos: start,
dir: Direction::Right,
},
|state| state.pos == end,
|state| self.adjacent(grid, state),
|curr, next| if curr.dir == next.dir { 1 } else { 1001 },
);
Direction::capital()
.into_iter()
.flat_map(|dir| {
result.get_paths(State { pos: end, dir }).into_iter()
})
.flat_map(|path| path.into_iter())
.map(|state| state.pos)
.unique()
.count()
}

fn samples(&self) {
aoc::puzzle_samples! {
self, part_1, TEST1, 7036,
self, part_1, TEST2, 11048,
self, part_2, TEST1, 45,
self, part_2, TEST2, 64
};
}
}

fn main() {
AoC2024_16 {}.run(std::env::args());
}

const TEST1: &str = "\
###############
#.......#....E#
#.#.###.#.###.#
#.....#.#...#.#
#.###.#####.#.#
#.#.#.......#.#
#.#.#####.###.#
#...........#.#
###.#.#####.#.#
#...#.....#.#.#
#.#.#.###.#.#.#
#.....#...#.#.#
#.###.#.#.#.#.#
#S..#.....#...#
###############
";
const TEST2: &str = "\
#################
#...#...#...#..E#
#.#.#.#.#.#.#.#.#
#.#.#.#...#...#.#
#.#.#.#.###.#.#.#
#...#.#.#.....#.#
#.#.#.#.#.#####.#
#.#...#.#.#.....#
#.#.#####.#.###.#
#.#.#.......#...#
#.#.###.#####.###
#.#.#...#.....#.#
#.#.#.#####.###.#
#.#.#.........#.#
#.#.#.#########.#
#S#.............#
#################
";

#[cfg(test)]
mod tests {
use super::*;

#[test]
pub fn samples() {
AoC2024_16 {}.samples();
}
}
24 changes: 16 additions & 8 deletions src/main/rust/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 76 additions & 2 deletions src/main/rust/aoc/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ pub struct Result<T> {
paths: HashMap<T, T>,
}

pub struct AllResults<T> {
start: T,
predecessors: HashMap<T, Vec<T>>,
}

impl<T> Result<T>
where
T: Eq + Copy + Hash,
Expand Down Expand Up @@ -142,6 +147,25 @@ where
}
}

impl<T> AllResults<T>
where
T: Eq + Copy + Hash,
{
pub fn get_paths(&self, t: T) -> Vec<Vec<T>> {
if t == self.start {
return vec![vec![self.start]];
}
let mut paths = vec![];
for predecessor in self.predecessors.get(&t).unwrap_or(&Vec::new()) {
for mut path in self.get_paths(*predecessor) {
path.push(t);
paths.push(path);
}
}
paths
}
}

impl<T> AStar<T>
where
T: Eq + Copy + Hash,
Expand Down Expand Up @@ -187,11 +211,61 @@ where
}
}

pub fn all(
start: T,
is_end: impl Fn(T) -> bool,
adjacent: impl Fn(T) -> Vec<T>,
cost: impl Fn(T, T) -> usize,
) -> AllResults<T> {
let mut q: BinaryHeap<State<T>> = BinaryHeap::new();
q.push(State {
node: start,
distance: 0,
});
let mut distances: HashMap<T, usize> = HashMap::new();
distances.insert(start, 0);
let mut predecessors: HashMap<T, Vec<T>> = HashMap::new();
while let Some(state) = q.pop() {
if is_end(state.node) {
break;
}
let total = *distances.get(&state.node).unwrap_or(&usize::MAX);
if state.distance > total {
continue;
}
adjacent(state.node).iter().for_each(|n| {
let risk = total + cost(state.node, *n);
let dist_n = *distances.get(n).unwrap_or(&usize::MAX);
match risk.cmp(&dist_n) {
Ordering::Less => {
distances.insert(*n, risk);
predecessors.entry(*n).insert_entry(vec![state.node]);
q.push(State {
node: *n,
distance: risk,
});
}
Ordering::Equal => {
predecessors
.entry(*n)
.and_modify(|e| e.push(state.node))
.or_insert(vec![state.node]);
}
_ => (),
}
});
}
AllResults {
start,
predecessors,
}
}

pub fn distance(
start: T,
is_end: impl Fn(T) -> bool,
adjacent: impl Fn(T) -> Vec<T>,
cost: impl Fn(T) -> usize,
cost: impl Fn(T, T) -> usize,
) -> usize {
let mut q: BinaryHeap<State<T>> = BinaryHeap::new();
q.push(State {
Expand All @@ -209,7 +283,7 @@ where
continue;
}
adjacent(state.node).iter().for_each(|n| {
let risk = total + cost(*n);
let risk = total + cost(state.node, *n);
if risk < *distances.get(n).unwrap_or(&usize::MAX) {
distances.insert(*n, risk);
q.push(State {
Expand Down

0 comments on commit 917caf5

Please sign in to comment.