implement day 15
This commit is contained in:
parent
403be5d4da
commit
726f629e30
57
src/day_15/mod.rs
Normal file
57
src/day_15/mod.rs
Normal file
|
@ -0,0 +1,57 @@
|
|||
mod model;
|
||||
mod parsing;
|
||||
|
||||
use aoc_runner_derive::{aoc, aoc_generator};
|
||||
pub use model::Grid;
|
||||
pub use parsing::parse_grid;
|
||||
use yap::IntoTokens;
|
||||
|
||||
#[aoc_generator(day15)]
|
||||
pub fn parse_input(input: &str) -> Grid {
|
||||
let grid = parse_grid(&mut input.into_tokens()).unwrap();
|
||||
Grid { grid }
|
||||
}
|
||||
|
||||
#[aoc(day15, part1)]
|
||||
pub fn part1(input: &Grid) -> usize {
|
||||
input.dijkstra((0, 0), (input.grid[0].len() - 1, input.grid.len() - 1))
|
||||
}
|
||||
|
||||
#[aoc(day15, part2)]
|
||||
pub fn part2(input: &Grid) -> usize {
|
||||
let input = input.grow();
|
||||
input.dijkstra((0, 0), (input.grid[0].len() - 1, input.grid.len() - 1))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
const EXAMPLE_INPUT: &str = "1163751742
|
||||
1381373672
|
||||
2136511328
|
||||
3694931569
|
||||
7463417111
|
||||
1319128137
|
||||
1359912421
|
||||
3125421639
|
||||
1293138521
|
||||
2311944581";
|
||||
const RESULT_PART_1: usize = 40;
|
||||
const RESULT_PART_2: usize = 315;
|
||||
|
||||
#[test]
|
||||
fn part1_example() {
|
||||
let result = super::part1(&super::parse_input(EXAMPLE_INPUT));
|
||||
assert_eq!(result, RESULT_PART_1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn part2_example() {
|
||||
let result = super::part2(&super::parse_input(EXAMPLE_INPUT));
|
||||
assert_eq!(result, RESULT_PART_2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_example() {
|
||||
super::parse_input(EXAMPLE_INPUT);
|
||||
}
|
||||
}
|
103
src/day_15/model.rs
Normal file
103
src/day_15/model.rs
Normal file
|
@ -0,0 +1,103 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use itertools::Itertools;
|
||||
|
||||
pub struct Grid {
|
||||
pub grid: Vec<Vec<usize>>,
|
||||
}
|
||||
|
||||
impl ToString for Grid {
|
||||
fn to_string(&self) -> String {
|
||||
self.grid
|
||||
.iter()
|
||||
.map(|line| {
|
||||
line.iter()
|
||||
.map(|digit| digit.to_string())
|
||||
.collect::<String>()
|
||||
})
|
||||
.join("\n")
|
||||
}
|
||||
}
|
||||
|
||||
impl Grid {
|
||||
pub fn dijkstra(&self, start: (usize, usize), end: (usize, usize)) -> usize {
|
||||
let mut cost = Vec::new();
|
||||
let mut prev = Vec::new();
|
||||
let mut dist = Vec::new();
|
||||
let mut visited = HashSet::new();
|
||||
let mut seen = HashSet::new();
|
||||
for y in 0..self.grid.len() {
|
||||
let mut cost_line = Vec::new();
|
||||
let mut prev_line = Vec::new();
|
||||
let mut dist_line = Vec::new();
|
||||
for x in 0..self.grid[y].len() {
|
||||
cost_line.push(self.grid[y][x]);
|
||||
prev_line.push(None);
|
||||
dist_line.push(None);
|
||||
}
|
||||
cost.push(cost_line);
|
||||
prev.push(prev_line);
|
||||
dist.push(dist_line);
|
||||
}
|
||||
|
||||
seen.insert((0, 0));
|
||||
dist[start.1][start.0] = Some(0);
|
||||
|
||||
loop {
|
||||
let min_square = seen
|
||||
.iter()
|
||||
//.filter(|s| !visited.contains(*s))
|
||||
.min_by(|a, b| {
|
||||
Ord::cmp(
|
||||
&dist[a.1][a.0].unwrap_or(usize::MAX),
|
||||
&dist[b.1][b.0].unwrap_or(usize::MAX),
|
||||
)
|
||||
})
|
||||
.cloned();
|
||||
if let Some((x, y)) = min_square {
|
||||
seen.remove(&(x, y));
|
||||
let current = (x, y);
|
||||
let current_dist = dist[current.1][current.0].unwrap();
|
||||
for (x_off, y_off) in [(-1, 0), (1, 0), (0, -1), (0, 1)] {
|
||||
let neighbour = ((x as isize + x_off) as usize, (y as isize + y_off) as usize);
|
||||
if !(cost.len() > neighbour.1 && cost[neighbour.1].len() > neighbour.0)
|
||||
|| visited.contains(&neighbour)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let neighbour_dist = dist[neighbour.1][neighbour.0].unwrap_or(usize::MAX);
|
||||
let neighbour_cost = cost[neighbour.1][neighbour.0];
|
||||
if neighbour_dist > current_dist + neighbour_cost {
|
||||
prev[neighbour.1][neighbour.0] = Some(current);
|
||||
dist[neighbour.1][neighbour.0] = Some(current_dist + neighbour_cost);
|
||||
seen.insert(neighbour);
|
||||
}
|
||||
}
|
||||
visited.insert(current);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
dist[end.1][end.0].unwrap()
|
||||
}
|
||||
|
||||
pub fn grow(&self) -> Self {
|
||||
let mut grid = Vec::new();
|
||||
let y_max = self.grid.len();
|
||||
let x_max = self.grid[0].len();
|
||||
for i in 0..5 {
|
||||
for y in 0..y_max {
|
||||
let mut line = Vec::new();
|
||||
for j in 0..5 {
|
||||
for x in 0..x_max {
|
||||
line.push(((self.grid[y][x] + i + j - 1) % 9) + 1)
|
||||
}
|
||||
}
|
||||
grid.push(line);
|
||||
}
|
||||
}
|
||||
Self { grid }
|
||||
}
|
||||
}
|
17
src/day_15/parsing.rs
Normal file
17
src/day_15/parsing.rs
Normal file
|
@ -0,0 +1,17 @@
|
|||
use yap::Tokens;
|
||||
|
||||
use crate::parsing::{newline, parse_digit};
|
||||
|
||||
pub fn parse_line(tokens: &mut impl Tokens<Item = char>) -> Option<Vec<usize>> {
|
||||
tokens.optional(|t| {
|
||||
let vec: Vec<usize> = t.many(|t| parse_digit(t)).collect();
|
||||
(!vec.is_empty()).then(|| vec)
|
||||
})
|
||||
}
|
||||
|
||||
pub fn parse_grid(tokens: &mut impl Tokens<Item = char>) -> Option<Vec<Vec<usize>>> {
|
||||
tokens.optional(|t| {
|
||||
let vec: Vec<Vec<usize>> = t.sep_by(|t| parse_line(t), |t| newline(t)).collect();
|
||||
(!vec.is_empty()).then(|| vec)
|
||||
})
|
||||
}
|
|
@ -16,5 +16,6 @@ pub mod day_11;
|
|||
pub mod day_12;
|
||||
pub mod day_13;
|
||||
pub mod day_14;
|
||||
pub mod day_15;
|
||||
|
||||
aoc_lib! { year = 2021 }
|
||||
|
|
Loading…
Reference in a new issue