Day 14, puzzle 1

This commit is contained in:
jazzpi 2022-12-16 09:46:19 +01:00
parent 6d3686c946
commit 215e067d33
4 changed files with 141 additions and 0 deletions

17
src/bin/d14p1.rs Normal file
View File

@ -0,0 +1,17 @@
use aoc22::{day14, util};
pub fn main() {
let mut cave = day14::parse_cave(&util::parse_input());
println!("Initial cave:");
cave.print();
let mut sand = 0;
while cave.drop_sand() {
sand += 1;
}
println!("Final cave:");
cave.print();
println!("Total sand dropped: {}", sand);
}

121
src/day14.rs Normal file
View File

@ -0,0 +1,121 @@
use std::collections::HashSet;
use itertools::Itertools;
use crate::util::Coord;
pub const SAND_SOURCE: Coord = (0, 500);
pub struct Cave {
pub rows: usize,
pub cols: usize,
pub blocked: Vec<Vec<bool>>,
pub sand_source: Coord,
}
impl Cave {
pub fn print(&self) {
for row in 0..self.rows {
for col in 0..self.cols {
if (row, col) == self.sand_source {
print!("+")
} else if self.blocked[row][col] {
print!("#");
} else {
print!(".");
}
}
print!("\n")
}
}
pub fn drop_sand(&mut self) -> bool {
let (y, x) = self.sand_source;
let mut y = y as isize;
let mut x = x as isize;
while y < self.rows as isize && x > 0 && x < self.cols as isize {
if !self.is_blocked(y + 1, x) {
y += 1;
} else if !self.is_blocked(y + 1, x - 1) {
y += 1;
x -= 1;
} else if !self.is_blocked(y + 1, x + 1) {
y += 1;
x += 1;
} else {
self.blocked[y as usize][x as usize] = true;
return true;
}
}
false
}
fn is_blocked(&self, y: isize, x: isize) -> bool {
!(y < 0 || y >= self.rows as isize || x < 0 || x >= self.cols as isize)
&& self.blocked[y as usize][x as usize]
}
}
pub fn parse_cave(input: &String) -> Cave {
let mut paths = HashSet::new();
for line in input.lines() {
let mut path = line.split("->").map(|n| parse_coord(n.trim()));
let mut last = path.next().unwrap();
paths.insert(last);
for next in path {
let y_min = next.0.min(last.0);
let y_max = next.0.max(last.0);
let x_min = next.1.min(last.1);
let x_max = next.1.max(last.1);
let horizontal = y_min == y_max;
let vertical = x_min == x_max;
assert!(horizontal ^ vertical);
if horizontal {
for x in x_min..=x_max {
paths.insert((y_min, x));
}
} else {
for y in y_min..=y_max {
paths.insert((y, x_max));
}
}
last = next;
}
}
assert_ne!(paths.len(), 0);
let (y_min, y_max) = paths.iter().map(|c| c.0).minmax().into_option().unwrap();
let (x_min, x_max) = paths.iter().map(|c| c.1).minmax().into_option().unwrap();
// Sand source is always at y = 0, x = 500
let y_min = y_min.min(SAND_SOURCE.0);
let x_min = x_min.min(SAND_SOURCE.1);
let x_max = x_max.max(SAND_SOURCE.1);
let rows = y_max - y_min + 1;
let cols = x_max - x_min + 1;
let mut blocked = vec![vec![false; cols]; rows];
for coord in paths {
blocked[coord.0 - y_min][coord.1 - x_min] = true;
}
Cave {
rows,
cols,
blocked,
sand_source: (SAND_SOURCE.0 - y_min, SAND_SOURCE.1 - x_min),
}
}
fn parse_coord(input: &str) -> Coord {
let (x, y) = input.split_once(',').unwrap();
(y.parse().unwrap(), x.parse().unwrap())
}

View File

@ -3,6 +3,7 @@ pub mod day10;
pub mod day11;
pub mod day12;
pub mod day13;
pub mod day14;
pub mod day2;
pub mod day3;
pub mod day4;

View File

@ -35,3 +35,5 @@ pub fn max_n<T: Ord + Copy>(slice: &[T], n: usize) -> Result<Vec<T>, ()> {
Ok(max_vals)
}
pub type Coord = (usize, usize);