This commit is contained in:
Joseph Montanaro 2021-12-31 08:25:28 -08:00
parent 33e9af89be
commit 5633d37773
3 changed files with 133 additions and 4 deletions

105
2021/src/day15.rs Normal file
View File

@ -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<Ordering> {
Some(self.cmp(other))
}
}
fn search(graph: &Vec2<usize>) -> 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<Vec2<usize>> {
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<usize>) -> Vec2<usize> {
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::<Vec<usize>>();
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))
}

View File

@ -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<Self::Item> {
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<T> Vec2<T> {
pub fn new(columns: usize) -> Vec2<T> {
@ -205,6 +225,10 @@ impl<T> Vec2<T> {
}
}
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<T: Display> Display for Vec2<T> {
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")?;

View File

@ -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();