From 5633d377734d307d6ca4c3955d2f5dbc279a2d36 Mon Sep 17 00:00:00 2001 From: Joseph Montanaro Date: Fri, 31 Dec 2021 08:25:28 -0800 Subject: [PATCH] day 15 --- 2021/src/day15.rs | 105 ++++++++++++++++++++++++++++++++++++++++++++++ 2021/src/lib.rs | 26 +++++++++++- 2021/src/main.rs | 6 +-- 3 files changed, 133 insertions(+), 4 deletions(-) create mode 100644 2021/src/day15.rs diff --git a/2021/src/day15.rs b/2021/src/day15.rs new file mode 100644 index 0000000..751100b --- /dev/null +++ b/2021/src/day15.rs @@ -0,0 +1,105 @@ +use color_eyre::eyre; + +use std::collections::{HashMap, BinaryHeap}; +use std::cmp::{Ord, PartialOrd, Ordering}; + +use crate::lib::Vec2; + + +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] +struct Node { + row: usize, + col: usize, + cost: usize, +} + +impl Ord for Node { + fn cmp(&self, other: &Self) -> Ordering { + other.cost.cmp(&self.cost) + .then_with(|| self.row.cmp(&other.row)) + .then_with(|| self.col.cmp(&other.col)) + } +} + +impl PartialOrd for Node { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + + +fn search(graph: &Vec2) -> usize { + // lifted shamelessly from https://doc.rust-lang.org/std/collections/binary_heap/index.html + let mut q = BinaryHeap::new(); + let start = Node {row: 0, col: 0, cost: 0}; + q.push(start); + let mut costs = HashMap::new(); + + while let Some(node) = q.pop() { + if node.row == graph.row_count() - 1 && node.col == graph.col_count() - 1 { + return node.cost; + } + if &node.cost > costs.get(&(node.row, node.col)).unwrap_or(&usize::MAX) { + continue; + } + + for (row, col) in graph.rect_neighbors(node.row, node.col) { + let hop_cost = graph.get(row, col); + let neighbor = Node {row, col, cost: node.cost + hop_cost}; + if &neighbor.cost < costs.get(&(row, col)).unwrap_or(&usize::MAX) { + q.push(neighbor); + costs.insert((row, col), neighbor.cost); + } + } + } + panic!("Could not find a path"); +} + + +fn load(data: &str) -> eyre::Result> { + let width = data.lines().next().unwrap().len(); + let mut grid = Vec2::new(width); + for line in data.lines() { + let chars = line.chars().map(|c| c.to_digit(10).unwrap() as usize); + grid.push(chars); + } + Ok(grid) +} + + +fn tile(grid: &Vec2) -> Vec2 { + let old_cols = grid.col_count(); + let new_cols = old_cols * 5; + let mut result = Vec2::new(new_cols); + for row in grid.rows() { + let values = (0..new_cols).map(|i| { + let v = row[i % old_cols] + i / old_cols; + (v - 1) % 9 + 1 + }); + result.push(values); + } + + let old_rows = grid.row_count(); + let new_rows = old_rows * 5; + for row_n in old_rows..new_rows { + let values = (0..new_cols).map(|c| { + let r = row_n % old_rows; + let v = result.get(r, c) + row_n / old_rows; + (v - 1) % 9 + 1 + }) + .collect::>(); + result.push(values.into_iter()); + } + result +} + + +pub fn run(data: &str) -> eyre::Result<(usize, usize)> { + let grid = load(data)?; + let grid2 = tile(&grid); + + let one = search(&grid); + let two = search(&grid2); + + Ok((one, two)) +} diff --git a/2021/src/lib.rs b/2021/src/lib.rs index e725aac..77c970d 100644 --- a/2021/src/lib.rs +++ b/2021/src/lib.rs @@ -147,6 +147,26 @@ impl Iterator for NeighborCoords { } +pub struct RectNeighbors { + nc: NeighborCoords, +} + +impl Iterator for RectNeighbors { + type Item = (usize, usize); + fn next(&mut self) -> Option { + if let Some((row, col)) = self.nc.next() { + if row == self.nc.start_row || col == self.nc.start_col { + return Some((row, col)); + } + else { + return self.next(); + } + } + return None + } +} + + #[allow(dead_code)] impl Vec2 { pub fn new(columns: usize) -> Vec2 { @@ -205,6 +225,10 @@ impl Vec2 { } } + pub fn rect_neighbors(&self, row: usize, col: usize) -> RectNeighbors { + RectNeighbors {nc: self.neighbor_coords(row, col)} + } + pub fn get(&self, row: usize, col: usize) -> &T { &self.data[self.offset(row, col)] } @@ -258,7 +282,7 @@ impl Display for Vec2 { for row in self.rows() { write!(f, "[")?; for (i, v) in row.iter().enumerate() { - if i > 0 {write!(f, ", ")?;} + if i > 0 {write!(f, "")?;} write!(f, "{}", v)?; } write!(f, "]\n")?; diff --git a/2021/src/main.rs b/2021/src/main.rs index 13e99ea..1c18e6b 100644 --- a/2021/src/main.rs +++ b/2021/src/main.rs @@ -4,14 +4,14 @@ use color_eyre::eyre; mod lib; use lib::load; -mod day14; +mod day15; fn main() -> eyre::Result<()> { - let data = load("data/14.txt")?; + let data = load("data/15.txt")?; let start = Instant::now(); - let (one, two) = day14::run(&data)?; + let (one, two) = day15::run(&data)?; let (dur, unit) = format_ns(start.elapsed().as_nanos()); let precision = 2.0 - dur.log10().floor();