Skip to content

Commit

Permalink
Day 17a
Browse files Browse the repository at this point in the history
  • Loading branch information
lpenz committed Dec 17, 2023
1 parent 1e9a1ba commit 3570f6d
Show file tree
Hide file tree
Showing 7 changed files with 329 additions and 0 deletions.
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ jobs:
- day14
- day15
- day16
- day17
if: github.ref == 'refs/heads/main'
needs: [ omnilint, rust ]
runs-on: ubuntu-latest
Expand Down
16 changes: 16 additions & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,5 +19,6 @@ members = [
"day14",
"day15",
"day16",
"day17",
]

10 changes: 10 additions & 0 deletions day17/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
[package]
name = "day17"
version = "0.1.0"
edition = "2021"

[dependencies]
aoc = { path = "../aoc" }
color-eyre = "0.6.2"
nom = "7.1.3"
sqrid = "0.0.23"
141 changes: 141 additions & 0 deletions day17/input.txt

Large diffs are not rendered by default.

86 changes: 86 additions & 0 deletions day17/src/bin/day17a.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Copyright (C) 2023 Leandro Lisboa Penz <lpenz@lpenz.org>
// This file is subject to the terms and conditions defined in
// file 'LICENSE', which is part of this source code package.

use day17::*;

use std::cmp::Reverse;
use std::collections::BinaryHeap;
use std::collections::HashMap;
use std::collections::HashSet;

pub type Heat = u32;

#[derive(Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)]
struct State {
pub pos: Pos,
pub lastdir: Option<Dir>,
pub dircount: usize,
}

fn process(size: u16, bufin: impl BufRead) -> Result<u32> {
let input = parser::parse(bufin)?;
let gheat = Grid::try_from(input)?;
let mut frontier = BinaryHeap::<(Reverse<Heat>, State)>::default();
frontier.push((Reverse(0), State::default()));
let mut visited = HashSet::<State>::default();
let mut heatacummap = HashMap::<State, Heat>::default();
heatacummap.insert(State::default(), 0);
let goal = Pos::try_from((size - 1, size - 1)).unwrap();
while let Some((_priority, st)) = frontier.pop() {
let pos = st.pos;
if visited.contains(&st) {
continue;
}
let heatacum = heatacummap[&st];
if pos == goal {
return Ok(heatacum);
}
for dir in Dir::iter::<false>() {
if st.lastdir == Some(-dir) || (st.lastdir == Some(dir) && st.dircount >= 3) {
// Gets wobbly
continue;
}
let Ok(newpos) = pos + dir else { continue };
let t = newpos.tuple();
if t.0 >= size || t.1 >= size {
continue;
}
let heatacum = heatacum + gheat[newpos];
let dircount = if Some(dir) == st.lastdir {
st.dircount + 1
} else {
1
};
let newst = State {
pos: newpos,
lastdir: Some(dir),
dircount,
};
let e = heatacummap.entry(newst).or_insert(heatacum);
if heatacum < *e {
*e = heatacum;
}
if visited.contains(&newst) {
continue;
}
let dist = Pos::manhattan(&newpos, &goal) as u32;
let priority = Reverse(heatacum + dist);
frontier.push((priority, newst));
}
visited.insert(st);
}
unreachable!();
}

#[test]
fn test() -> Result<()> {
let start = std::time::Instant::now();
assert_eq!(process(13, EXAMPLE.as_bytes())?, 102);
println!("Elapsed: {}", elapsed(&start));
Ok(())
}

fn main() -> Result<()> {
do_main(|| process(141, stdin().lock()))
}
74 changes: 74 additions & 0 deletions day17/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// Copyright (C) 2023 Leandro Lisboa Penz <lpenz@lpenz.org>
// This file is subject to the terms and conditions defined in
// file 'LICENSE', which is part of this source code package.

pub use aoc::*;

pub const EXAMPLE: &str = "2413432311323
3215453535623
3255245654254
3446585845452
4546657867536
1438598798454
4457876987766
3637877979653
4654967986887
4564679986453
1224686865563
2546548887735
4322674655533
";

pub type Cell = u32;

pub mod parser {
use aoc::parser::*;

use super::*;

fn cell(input: &str) -> IResult<&str, Cell> {
let (input, val) = character::one_of("0123456789")(input)?;
Ok((input, val.to_digit(10).unwrap()))
}

fn line(input: &str) -> IResult<&str, Vec<Cell>> {
let (input, cells) = multi::many1(cell)(input)?;
let (input, _) = character::newline(input)?;
Ok((input, cells))
}

pub fn parse(mut bufin: impl BufRead) -> Result<Vec<Vec<Cell>>> {
aoc::parse_with!(multi::many1(line), bufin)
}
}

#[test]
fn test() -> Result<()> {
let input = parser::parse(EXAMPLE.as_bytes())?;
assert_eq!(input.len(), 13);
assert_eq!(input[0].len(), 13);
Ok(())
}

pub use sqrid::Dir;
pub type Sqrid = sqrid::sqrid_create!(141, 141, false);
// pub type Sqrid = sqrid::sqrid_create!(13, 13, false);
pub type Pos = sqrid::pos_create!(Sqrid);
pub type Grid = sqrid::grid_create!(Sqrid, u32);

pub type Griddir = sqrid::grid_create!(Sqrid, String);

pub fn path_debug(_size: u16, gheat: &Grid, path: &[Dir]) {
let mut gheatacum = Grid::default();
let mut pos = Pos::TOP_LEFT;
let mut heat = 0;
let mut gdir = Griddir::default();
for dir in path {
gdir[pos] = dir.name_utf8().to_string();
pos = (pos + dir).unwrap();
heat += gheat[pos];
gheatacum[pos] = heat;
}
eprintln!("{:1}", gdir);
eprintln!("{:>4}", gheatacum);
}

0 comments on commit 3570f6d

Please sign in to comment.