use std::collections::HashSet; use base::read_file; #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] struct Pos(i32, i32); #[derive(Copy, Clone, Debug, Eq, PartialEq)] struct Line(Pos, Pos); impl Line { fn contains(&self, p: &Pos) -> bool { let Pos(x1, y1) = self.0; let Pos(x2, y2) = self.1; let x_max = x1.max(x2); let x_min = x1.min(x2); let y_max = y1.max(y2); let y_min = y1.min(y2); return if x1 == x2 { let y_range = y_min..=y_max; p.0 == x1 && y_range.contains(&p.1) } else if y1 == y2 { let x_range = x_min..=x_max; x_range.contains(&p.0) && p.1 == y1 } else { false }; } } impl Pos { fn can_move_to(&self, relative: &Pos, lines: &Vec, others: &HashSet) -> bool { let relative = Pos(self.0 + relative.0, self.1 + relative.1); for line in lines { if line.contains(&relative) { return false; } } !others.contains(&relative) } } fn do_simulation(rock_lines: &Vec, max_height: i32) -> u32 { let mut spawns = 0; let mut sands = HashSet::new(); let sand_spawn = Pos(500, 0); let mut sand = sand_spawn; loop { if sand.can_move_to(&Pos(0, 1), &rock_lines, &sands) { sand = Pos(sand.0, sand.1 + 1); } else if sand.can_move_to(&Pos(-1, 1), &rock_lines, &sands) { sand = Pos(sand.0 - 1, sand.1 + 1); } else if sand.can_move_to(&Pos(1, 1), &rock_lines, &sands) { sand = Pos(sand.0 + 1, sand.1 + 1); } else { if sand == sand_spawn { spawns += 1; break; } sands.insert(sand); sand = sand_spawn; spawns += 1; } if sand.1 == max_height { println!("Sand reached void"); break; } } spawns } fn main() { let lines = read_file("day14.txt"); let mut rock_lines = vec![]; for x in lines { x.split_whitespace().filter(|s| !(s == &"->")).map(|s| { let mut split = s.split(','); let x = split.next().unwrap().parse().unwrap(); let y = split.next().unwrap().parse().unwrap(); Pos(x, y) }).collect::>().windows(2).map(|pos| Line(pos[0], pos[1])).collect::>().iter().for_each(|line| rock_lines.push(*line)); } let max_height = rock_lines.iter().flat_map(|line| [line.0.1, line.1.1]).max().unwrap() + 1; println!("Everything above {max_height} is void"); let task1 = do_simulation(&rock_lines, max_height); println!("Task1: Got {task1} spawns"); rock_lines.push(Line(Pos(i32::MIN, max_height + 1), Pos(i32::MAX, max_height + 1))); let task2 = do_simulation(&rock_lines, i32::MAX); println!("Task2: Got {task2} spawns"); }