Skip to content

Commit

Permalink
AoC 2024 Day 20 - rust
Browse files Browse the repository at this point in the history
  • Loading branch information
pareronia committed Dec 21, 2024
1 parent 93f92db commit a24749e
Show file tree
Hide file tree
Showing 6 changed files with 204 additions and 1 deletion.
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) | [](src/main/python/AoC2024_17.py) | [](src/main/python/AoC2024_18.py) | [](src/main/python/AoC2024_19.py) | [](src/main/python/AoC2024_20.py) | [](src/main/python/AoC2024_21.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_11/src/main.rs) | [](src/main/rust/AoC2024_12/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) | [](src/main/rust/AoC2024_17/src/main.rs) | [](src/main/rust/AoC2024_18/src/main.rs) | [](src/main/rust/AoC2024_19/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_11/src/main.rs) | [](src/main/rust/AoC2024_12/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) | [](src/main/rust/AoC2024_17/src/main.rs) | [](src/main/rust/AoC2024_18/src/main.rs) | [](src/main/rust/AoC2024_19/src/main.rs) | [](src/main/rust/AoC2024_20/src/main.rs) | | | | | |
<!-- @END:ImplementationsTable:2024@ -->

## 2023
Expand Down
7 changes: 7 additions & 0 deletions src/main/rust/AoC2024_20/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
[package]
name = "AoC2024_20"
version = "0.1.0"
edition = "2021"

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

use aoc::graph::BFS;
use aoc::grid::{CharGrid, Grid};
use aoc::Puzzle;

struct AoC2024_20;

impl AoC2024_20 {
fn solve(&self, grid: &CharGrid, cheat_len: usize, target: usize) -> usize {
let start = grid.find_first_matching(|ch| ch == 'S').unwrap();
let distances = BFS::execute_full(
start,
|cell| grid.get(&cell) != '#',
|cell| {
grid.capital_neighbours(&cell)
.into_iter()
.filter(|n| grid.get(n) != '#')
.collect()
},
);
let mut ans = 0;
for cell in distances.keys() {
for md in 2..cheat_len + 1 {
for n in cell.get_all_at_manhattan_distance(md) {
if !distances.contains_key(&n) {
continue;
}
if distances[&n] < distances[cell] {
continue;
}
if distances[&n] - distances[cell] >= target + md {
ans += 1;
}
}
}
}
ans
}
fn sample_part_1(&self, grid: &CharGrid) -> usize {
self.solve(grid, 2, 2)
}

fn sample_part_2(&self, grid: &CharGrid) -> usize {
self.solve(grid, 20, 50)
}
}

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

aoc::puzzle_year_day!(2024, 20);

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 {
self.solve(grid, 2, 100)
}

fn part_2(&self, grid: &Self::Input) -> Self::Output2 {
self.solve(grid, 20, 100)
}

fn samples(&self) {
aoc::puzzle_samples! {
self, sample_part_1, TEST, 44,
self, sample_part_2, TEST, 285
};
}
}

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

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

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

#[test]
pub fn samples() {
AoC2024_20 {}.samples();
}
}
7 changes: 7 additions & 0 deletions src/main/rust/Cargo.lock

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

63 changes: 63 additions & 0 deletions src/main/rust/aoc/src/graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,36 @@ where
unreachable!();
}

pub fn execute_full(
start: T,
is_end: impl Fn(T) -> bool,
adjacent: impl Fn(T) -> Vec<T>,
) -> HashMap<T, usize> {
let mut q: VecDeque<State<T>> = VecDeque::new();
q.push_back(State {
node: start,
distance: 0,
});
let mut seen: HashSet<T> = HashSet::new();
seen.insert(start);
let mut distances: HashMap<T, usize> = HashMap::new();
while let Some(state) = q.pop_front() {
if is_end(state.node) {
distances.insert(state.node, state.distance);
}
adjacent(state.node).iter().for_each(|n| {
if !seen.contains(n) {
seen.insert(*n);
q.push_back(State {
node: *n,
distance: state.distance + 1,
});
}
});
}
distances
}

pub fn flood_fill(start: T, adjacent: impl Fn(T) -> Vec<T>) -> HashSet<T> {
let mut q: VecDeque<T> = VecDeque::new();
q.push_back(start);
Expand Down Expand Up @@ -333,6 +363,39 @@ mod tests {
bfs_execute(Cell::at(0, 0), Cell::at(4, 0));
}

fn bfs_execute_full(start: Cell) -> HashMap<Cell, usize> {
#[rustfmt::skip]
let v = &vec![
".###",
"..##",
"#..#",
"##..",
"###."];
let grid = CharGrid::from(&v);
let adjacent = |cell| {
grid.capital_neighbours(&cell)
.iter()
.filter(|n| grid.get(&n) != '#')
.cloned()
.collect()
};
BFS::execute_full(start, |cell| grid.get(&cell) == '.', adjacent)
}

#[test]
pub fn bfs_execute_full_ok() {
let dist = bfs_execute_full(Cell::at(0, 0));
assert_eq!(dist.len(), 8);
assert_eq!(dist[&Cell::at(0, 0)], 0);
assert_eq!(dist[&Cell::at(1, 0)], 1);
assert_eq!(dist[&Cell::at(1, 1)], 2);
assert_eq!(dist[&Cell::at(2, 1)], 3);
assert_eq!(dist[&Cell::at(2, 2)], 4);
assert_eq!(dist[&Cell::at(3, 2)], 5);
assert_eq!(dist[&Cell::at(3, 3)], 6);
assert_eq!(dist[&Cell::at(4, 3)], 7);
}

#[test]
pub fn bfs_flood_fill() {
#[rustfmt::skip]
Expand Down
20 changes: 20 additions & 0 deletions src/main/rust/aoc/src/grid.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::geometry::XY;
use itertools::Itertools;
use std::cmp::Ordering;
use std::collections::HashSet;
use std::fmt::{Display, Error, Formatter};

#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
Expand Down Expand Up @@ -61,6 +62,25 @@ impl Cell {
}
ans
}

#[allow(clippy::needless_lifetimes)]
pub fn get_all_at_manhattan_distance<'a>(
&'a self,
distance: usize,
) -> impl Iterator<Item = Cell> + 'a {
(0..=distance).flat_map(move |dr| {
let dc = distance - dr;
let set = HashSet::from([
(self.row.checked_add(dr), self.col.checked_add(dc)),
(self.row.checked_add(dr), self.col.checked_sub(dc)),
(self.row.checked_sub(dr), self.col.checked_add(dc)),
(self.row.checked_sub(dr), self.col.checked_sub(dc)),
]);
set.into_iter()
.filter(|(rr, cc)| rr.is_some() && cc.is_some())
.map(|(rr, cc)| Cell::at(rr.unwrap(), cc.unwrap()))
})
}
}

impl PartialOrd for Cell {
Expand Down

0 comments on commit a24749e

Please sign in to comment.