day 10 part 1 first attempt

This commit is contained in:
Dominic 2023-12-10 10:02:45 +01:00
parent fe9cf52452
commit 998dfd5c61
Signed by: msrd0
GPG key ID: DCC8C247452E98F9
2 changed files with 286 additions and 0 deletions

146
src/bin/day10.rs Normal file
View file

@ -0,0 +1,146 @@
#![forbid(elided_lifetimes_in_paths, unsafe_code)]
use aoc23::read;
use chumsky::prelude::*;
use std::{
collections::{BTreeSet, HashMap, HashSet},
fmt::{self, Debug}
};
macro_rules! cells {
($($ident:ident = $char:literal),+) => {
#[derive(Clone, Copy, Eq, Hash, PartialEq, PartialOrd, Ord)]
enum Cell { $($ident),+ }
impl Cell {
fn parser() -> impl Parser<char, Self, Error = Simple<char>> {
choice((
$(just($char).map(|_| Self::$ident)),+
))
}
}
impl Debug for Cell {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
$(Self::$ident => write!(f, "{}", $char)),+
}
}
}
}
}
cells! {
NorthSouthPipe = '|',
EastWestPipe = '-',
NorthEastPipe = 'L',
NorthWestPipe = 'J',
SouthWestPipe = '7',
SouthEastPipe = 'F',
Ground = '.',
Start = 'S'
}
fn parser() -> impl Parser<char, Vec<Vec<Cell>>, Error = Simple<char>> {
Cell::parser()
.repeated()
.then_ignore(just("\n"))
.repeated()
.then_ignore(end())
}
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
struct Node {
row: usize,
col: usize
}
#[derive(Default)]
struct AdjList(HashMap<Node, HashSet<Node>>);
impl AdjList {
fn add_edge(&mut self, from: Node, to: Node) {
self.0.entry(from).or_default().insert(to);
// doesn't work that way due to the way we handle start
// self.0.entry(to).or_default().insert(from);
}
fn dij(&self, start: Node) -> HashMap<Node, usize> {
let mut dists = HashMap::new();
let mut q: BTreeSet<(usize, Node)> = BTreeSet::new();
dists.insert(start, 0);
q.insert((0, start));
while let Some((dist, node)) = q.pop_first() {
for next in self.0.get(&node).into_iter().flatten() {
let next_dist = dists.get(next);
if next_dist.map(|d| *d > dist + 1).unwrap_or(true) {
if let Some(old_dist) = next_dist {
q.remove(&(*old_dist, *next));
}
dists.insert(*next, dist + 1);
q.insert((dist + 1, *next));
}
}
}
dists
}
}
const NORTH: (isize, isize) = (-1, 0);
const EAST: (isize, isize) = (0, 1);
const SOUTH: (isize, isize) = (1, 0);
const WEST: (isize, isize) = (0, -1);
fn main() -> anyhow::Result<()> {
let grid = read("inputs/day10.txt", parser())?;
let mut adj = AdjList::default();
let mut start = None;
for i in 0 .. grid.len() {
for j in 0 .. grid[i].len() {
let node = Node { row: i, col: j };
let others: &[(isize, isize)] = match grid[i][j] {
Cell::NorthSouthPipe => &[NORTH, SOUTH],
Cell::EastWestPipe => &[EAST, WEST],
Cell::NorthEastPipe => &[NORTH, EAST],
Cell::NorthWestPipe => &[NORTH, WEST],
Cell::SouthWestPipe => &[SOUTH, WEST],
Cell::SouthEastPipe => &[SOUTH, EAST],
Cell::Ground => &[],
Cell::Start => {
assert!(start.is_none());
start = Some(node);
// we can do this but that means in dijkstra we need to handle
// connections going nowhere
&[NORTH, EAST, SOUTH, WEST]
}
};
for (row_diff, col_diff) in others {
let other = match (
i.checked_add_signed(*row_diff),
j.checked_add_signed(*col_diff)
) {
(Some(row), Some(col)) if row < grid.len() && col < grid[i].len() => {
Node { row, col }
},
_ => continue
};
adj.add_edge(node, other);
}
}
}
// 6749 is too low
println!(
"{:?}",
adj.dij(start.unwrap())
.into_iter()
.max_by_key(|(_, dist)| *dist)
.unwrap()
);
Ok(())
}