86 lines
2.8 KiB
Rust
86 lines
2.8 KiB
Rust
|
use std::fs;
|
||
|
use std::str::FromStr;
|
||
|
use std::collections::HashMap;
|
||
|
|
||
|
fn main() {
|
||
|
const FILE_PATH: &str = "input";
|
||
|
println!("Hi this is the fourteenth day of AOC2022, first we will read the file {}", FILE_PATH);
|
||
|
let contents = fs::read_to_string(FILE_PATH)
|
||
|
.expect("Should have been able to read the file");
|
||
|
|
||
|
println!("The ammount of grains of sand with void are: {}", throw_sand_untill_timeout(parse(&contents), (500, 0)).iter().filter(|h| *h.1).count());
|
||
|
println!("The ammount of grains of sand with a floor are: {}", throw_sand_untill_timeout(add_floor(parse(&contents)), (500, 0)).iter().filter(|h| *h.1).count());
|
||
|
}
|
||
|
|
||
|
use std::cmp::{max,min};
|
||
|
fn parse(s: &str) -> HashMap<(usize, usize), bool> {
|
||
|
let mut cave = HashMap::new();
|
||
|
for line in s.lines(){
|
||
|
let coords: Vec<_> = line.split(" -> ").map(|t| (usize::from_str(t.split(",").next().expect("must exist")).expect("NaN"),usize::from_str(t.split(",").skip(1).next().expect("must exist")).expect("NaN"))).collect();
|
||
|
for range in coords.windows(2){
|
||
|
let (ix, iy) = range[0];
|
||
|
let (fx, fy) = range[1];
|
||
|
for i in min(ix, fx)..=max(ix, fx){
|
||
|
for j in min(iy, fy)..=max(iy, fy){
|
||
|
cave.insert((i,j), false);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
cave
|
||
|
}
|
||
|
|
||
|
fn throw_sand(mut cave: HashMap<(usize, usize), bool>, hole: (usize, usize)) -> (HashMap<(usize, usize), bool>, bool){
|
||
|
let mut timeout = 0;
|
||
|
let (mut sx, mut sy) = hole;
|
||
|
while timeout < 200{
|
||
|
if !cave.contains_key(&(sx, sy + 1)){
|
||
|
sy +=1;
|
||
|
}else if !cave.contains_key(&(sx-1, sy + 1)){
|
||
|
sy +=1;
|
||
|
sx -=1;
|
||
|
}else if !cave.contains_key(&(sx+1, sy + 1)){
|
||
|
sy +=1;
|
||
|
sx +=1;
|
||
|
}else{
|
||
|
if let Some(_) = cave.insert((sx, sy), true){
|
||
|
return (cave, true);
|
||
|
}else{
|
||
|
return (cave, false);
|
||
|
}
|
||
|
}
|
||
|
timeout +=1;
|
||
|
}
|
||
|
(cave, true)
|
||
|
}
|
||
|
|
||
|
fn throw_sand_untill_timeout(mut cave: HashMap<(usize, usize), bool>, hole: (usize, usize)) -> HashMap<(usize, usize), bool>{
|
||
|
loop {
|
||
|
let (binding, timeout) = throw_sand(cave, hole);
|
||
|
cave = binding;
|
||
|
if timeout {break cave;}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
fn add_floor(mut cave: HashMap<(usize, usize), bool>) -> HashMap<(usize, usize), bool>{
|
||
|
let floor = *cave.iter().map(|((_, y), _)| y).max().expect("must have a lowest point")+2;
|
||
|
for i in 0..=1000{
|
||
|
cave.insert((i, floor), false);
|
||
|
}
|
||
|
cave
|
||
|
}
|
||
|
|
||
|
#[cfg(test)]
|
||
|
mod test {
|
||
|
const INPUT: &str = r#"498,4 -> 498,6 -> 496,6
|
||
|
503,4 -> 502,4 -> 502,9 -> 494,9"#;
|
||
|
use super::*;
|
||
|
#[test]
|
||
|
fn sand1() {
|
||
|
assert_eq!(throw_sand_untill_timeout(parse(INPUT), (500, 0)).iter().filter(|h| *h.1).count(), 24);
|
||
|
}
|
||
|
#[test]
|
||
|
fn sand2() {
|
||
|
assert_eq!(throw_sand_untill_timeout(add_floor(parse(INPUT)), (500, 0)).iter().filter(|h| *h.1).count(), 93);
|
||
|
}
|
||
|
}
|