Advertisement
nairby

2022 Day 14

Dec 14th, 2022
1,359
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 3.74 KB | None | 0 0
  1. use std::env;
  2. use std::io::{self, prelude::*, BufReader};
  3. use std::fs::File;
  4. use std::collections::HashMap;
  5.  
  6. use point2d::point2d::Point2D;
  7.  
  8. const ORIGIN_X: i64 = 500;
  9. const ORIGIN_Y: i64 = 0;
  10. const ORIGIN: Point2D = Point2D { x: ORIGIN_X, y: ORIGIN_Y };
  11.  
  12. enum MapType {
  13.     Origin,
  14.     Rock,
  15.     Sand,
  16. }
  17.  
  18. fn can_move(sand_map: &HashMap<Point2D,MapType>, pt: &Point2D) -> bool {
  19.     match sand_map.get(&pt) {
  20.         None => true,
  21.         Some(_) => false,
  22.     }
  23. }
  24.  
  25. fn drop_sand(sand_map: &mut HashMap<Point2D,MapType>, abyss: i64, part1: bool) -> bool {
  26.  
  27.     let mut new_pt = Point2D { x: ORIGIN_X, y: ORIGIN_Y };
  28.     loop {
  29.  
  30.         // Assess movements
  31.         let try_down  = Point2D { x: new_pt.x,   y: new_pt.y+1 };
  32.         let try_left  = Point2D { x: new_pt.x-1, y: new_pt.y+1 };
  33.         let try_right = Point2D { x: new_pt.x+1, y: new_pt.y+1 };
  34.  
  35.         let can_down  = can_move(&sand_map, &try_down);
  36.         let can_left  = can_move(&sand_map, &try_left);
  37.         let can_right = can_move(&sand_map, &try_right);
  38.  
  39.         // Assign movements
  40.         if can_down {
  41.             new_pt = try_down;
  42.             if part1 && new_pt.y + 1 == abyss { return false; } // Fell to the abyss
  43.         } else if can_left {
  44.             new_pt = try_left;
  45.         } else if can_right {
  46.             new_pt = try_right;
  47.         } else {
  48.             if !part1 && new_pt == ORIGIN { return false; } // Blocking origin
  49.             sand_map.insert(new_pt,MapType::Sand);
  50.             return true; // At rest
  51.         }
  52.     }
  53. }
  54.  
  55. fn build_map(input: &Vec<String>) -> HashMap<Point2D,MapType> {
  56.     let mut sand_map: HashMap<Point2D,MapType> = HashMap::new();
  57.     let origin = Point2D { x: ORIGIN_X, y: ORIGIN_Y };
  58.     sand_map.insert(origin, MapType::Origin);
  59.     for line in input {
  60.         let segments: Vec<_> = line.split("->").collect();
  61.         for segment in segments.windows(2) {
  62.             let p1: Vec<_> = segment[0].split(",").map(|v| v.trim().parse::<i64>().unwrap()).collect();
  63.             let p2: Vec<_> = segment[1].split(",").map(|v| v.trim().parse::<i64>().unwrap()).collect();
  64.             let (x1,y1) = (p1[0], p1[1]);
  65.             let (x2,y2) = (p2[0], p2[1]);
  66.             let xrange = if x2 > x1 { x1..=x2 } else { x2..=x1 };
  67.             let yrange = if y2 > y1 { y1..=y2 } else { y2..=y1 };
  68.             for x in xrange.clone() {
  69.                 for y in yrange.clone() {
  70.                     sand_map.insert(Point2D { x: x, y: y }, MapType::Rock);
  71.                 }
  72.             }
  73.         }
  74.     }
  75.     sand_map
  76. }
  77.  
  78. fn solve(input: &str) -> io::Result<()> {
  79.     let file = File::open(input).expect("Input file not found.");
  80.     let reader = BufReader::new(file);
  81.  
  82.     // Input
  83.     let input: Vec<String> = match reader.lines().collect() {
  84.         Err(err) => panic!("Unknown error reading input: {}", err),
  85.         Ok(result) => result,
  86.     };
  87.  
  88.     // Part 1
  89.     let mut sand_map = build_map(&input);
  90.  
  91.     // Identify the extent of the abyss
  92.     let abyss = &sand_map.keys().map(|&pt| pt.y).max().unwrap() + 2;
  93.  
  94.     // Simulate sand
  95.     'sand_lp: for sand in 0.. {
  96.        let result = drop_sand(&mut sand_map,abyss,true);
  97.        if !result { println!("Part 1: {sand}"); break 'sand_lp; } // 1061
  98.     }
  99.  
  100.     // Part 2 (reset map)
  101.     let mut sand_map = build_map(&input);
  102.  
  103.     // Build floor
  104.     for x in 0..=1000 {
  105.         sand_map.insert(Point2D { x: x, y: abyss },MapType::Rock);
  106.     }
  107.  
  108.     'sand_lp2: for sand in 1.. {
  109.        let result = drop_sand(&mut sand_map,abyss,false);
  110.        if !result { println!("Part 2: {sand}"); break 'sand_lp2; } //  25055
  111.     }
  112.  
  113.     Ok(())
  114. }
  115.  
  116. fn main() {
  117.     let args: Vec<String> = env::args().collect();
  118.     let filename = &args[1];
  119.     solve(&filename).unwrap();
  120. }
  121.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement