From 1606cb77ab2e7e9bfbe97d8cdac564d95132fde0 Mon Sep 17 00:00:00 2001 From: Leandro Lisboa Penz Date: Sun, 17 Dec 2023 08:56:12 +0000 Subject: [PATCH] Day 17a --- .github/workflows/ci.yml | 1 + Cargo.lock | 16 ++++++++ Cargo.toml | 1 + day17/Cargo.toml | 10 +++++ day17/src/bin/day17a.rs | 83 ++++++++++++++++++++++++++++++++++++++++ day17/src/lib.rs | 74 +++++++++++++++++++++++++++++++++++ 6 files changed, 185 insertions(+) create mode 100644 day17/Cargo.toml create mode 100644 day17/src/bin/day17a.rs create mode 100644 day17/src/lib.rs diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e33a799..fe14da5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -33,6 +33,7 @@ jobs: - day14 - day15 - day16 + - day17 part: [ a, b ] if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest diff --git a/Cargo.lock b/Cargo.lock index 04c58c7..1f17046 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -305,6 +305,16 @@ dependencies = [ "sqrid 0.0.22", ] +[[package]] +name = "day17" +version = "0.1.0" +dependencies = [ + "aoc", + "color-eyre", + "nom", + "sqrid 0.0.23", +] + [[package]] name = "either" version = "1.9.0" @@ -591,6 +601,12 @@ version = "0.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92bfab44888e2fc47178beb71e1ad84bd2a97361a6943019a8602f214ae4c126" +[[package]] +name = "sqrid" +version = "0.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfa174f70d3ecc8171ef9784a74bac0689af9ce41b01d00732a132465f985f3a" + [[package]] name = "thread_local" version = "1.1.7" diff --git a/Cargo.toml b/Cargo.toml index 0ca9120..ebeb64c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,5 +19,6 @@ members = [ "day14", "day15", "day16", + "day17", ] diff --git a/day17/Cargo.toml b/day17/Cargo.toml new file mode 100644 index 0000000..0f2ffc2 --- /dev/null +++ b/day17/Cargo.toml @@ -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" diff --git a/day17/src/bin/day17a.rs b/day17/src/bin/day17a.rs new file mode 100644 index 0000000..c07d590 --- /dev/null +++ b/day17/src/bin/day17a.rs @@ -0,0 +1,83 @@ +// Copyright (C) 2023 Leandro Lisboa Penz +// 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; + +#[derive(Debug, Default, Hash, PartialEq, Eq, PartialOrd, Ord, Clone, Copy)] +struct State { + pub lastdir: Option, + pub dircount: usize, + pub heatacum: u32, +} + +fn process(size: u16, bufin: impl BufRead) -> Result { + let input = parser::parse(bufin)?; + let gheat = Grid::try_from(input)?; + let orig = Pos::TOP_LEFT; + let mut heatmap: HashMap<_, _> = [(orig, 0)].into_iter().collect(); + let mut statemap = HashMap::<(u32, Pos), HashSet>::default(); + statemap.insert((0, Pos::TOP_LEFT), [State::default()].into_iter().collect()); + let mut frontier: BinaryHeap<_> = [Reverse((0, Pos::TOP_LEFT))].into_iter().collect(); + let mut visited = HashSet::<(Pos, State)>::default(); + let goal = Pos::try_from((size - 1, size - 1)).unwrap(); + while let Some(key) = frontier.pop() { + let pos = key.0 .1; + let sts = statemap[&key.0].clone(); + for st in sts { + if visited.contains(&(pos, st)) { + continue; + } + if pos == goal { + return Ok(st.heatacum); + } + for dir in Dir::iter::() { + if st.lastdir == Some(-dir) || (st.lastdir == Some(dir) && st.dircount >= 3) { + continue; + } + if let Ok(newpos) = pos + dir { + let t = newpos.tuple(); + if t.0 >= size || t.1 >= size { + continue; + } + let heatacum = st.heatacum + gheat[newpos]; + let eheat = heatmap.entry(newpos).or_insert(u32::MAX); + if true { + // heatacum <= *eheat { + let dircount = if Some(dir) == st.lastdir { + st.dircount + 1 + } else { + 1 + }; + let newst = State { + lastdir: Some(dir), + dircount, + heatacum, + }; + *eheat = heatacum; + let e = statemap.entry((heatacum, newpos)).or_default(); + e.insert(newst); + frontier.push(Reverse((heatacum, newpos))); + } + } + } + visited.insert((pos, st)); + } + } + unreachable!(); +} + +#[test] +fn test() -> Result<()> { + assert_eq!(process(13, EXAMPLE.as_bytes())?, 102); + Ok(()) +} + +fn main() -> Result<()> { + do_main(|| process(141, stdin().lock())) +} diff --git a/day17/src/lib.rs b/day17/src/lib.rs new file mode 100644 index 0000000..5e247d8 --- /dev/null +++ b/day17/src/lib.rs @@ -0,0 +1,74 @@ +// Copyright (C) 2023 Leandro Lisboa Penz +// 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> { + let (input, cells) = multi::many1(cell)(input)?; + let (input, _) = character::newline(input)?; + Ok((input, cells)) + } + + pub fn parse(mut bufin: impl BufRead) -> Result>> { + 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); +}