Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::env;
- use std::io::{self, prelude::*, BufReader};
- use std::fs::File;
- use std::collections::HashMap;
- use point2d::point2d::Point2D;
- const ORIGIN_X: i64 = 500;
- const ORIGIN_Y: i64 = 0;
- const ORIGIN: Point2D = Point2D { x: ORIGIN_X, y: ORIGIN_Y };
- enum MapType {
- Origin,
- Rock,
- Sand,
- }
- fn can_move(sand_map: &HashMap<Point2D,MapType>, pt: &Point2D) -> bool {
- match sand_map.get(&pt) {
- None => true,
- Some(_) => false,
- }
- }
- fn drop_sand(sand_map: &mut HashMap<Point2D,MapType>, abyss: i64, part1: bool) -> bool {
- let mut new_pt = Point2D { x: ORIGIN_X, y: ORIGIN_Y };
- loop {
- // Assess movements
- let try_down = Point2D { x: new_pt.x, y: new_pt.y+1 };
- let try_left = Point2D { x: new_pt.x-1, y: new_pt.y+1 };
- let try_right = Point2D { x: new_pt.x+1, y: new_pt.y+1 };
- let can_down = can_move(&sand_map, &try_down);
- let can_left = can_move(&sand_map, &try_left);
- let can_right = can_move(&sand_map, &try_right);
- // Assign movements
- if can_down {
- new_pt = try_down;
- if part1 && new_pt.y + 1 == abyss { return false; } // Fell to the abyss
- } else if can_left {
- new_pt = try_left;
- } else if can_right {
- new_pt = try_right;
- } else {
- if !part1 && new_pt == ORIGIN { return false; } // Blocking origin
- sand_map.insert(new_pt,MapType::Sand);
- return true; // At rest
- }
- }
- }
- fn build_map(input: &Vec<String>) -> HashMap<Point2D,MapType> {
- let mut sand_map: HashMap<Point2D,MapType> = HashMap::new();
- let origin = Point2D { x: ORIGIN_X, y: ORIGIN_Y };
- sand_map.insert(origin, MapType::Origin);
- for line in input {
- let segments: Vec<_> = line.split("->").collect();
- for segment in segments.windows(2) {
- let p1: Vec<_> = segment[0].split(",").map(|v| v.trim().parse::<i64>().unwrap()).collect();
- let p2: Vec<_> = segment[1].split(",").map(|v| v.trim().parse::<i64>().unwrap()).collect();
- let (x1,y1) = (p1[0], p1[1]);
- let (x2,y2) = (p2[0], p2[1]);
- let xrange = if x2 > x1 { x1..=x2 } else { x2..=x1 };
- let yrange = if y2 > y1 { y1..=y2 } else { y2..=y1 };
- for x in xrange.clone() {
- for y in yrange.clone() {
- sand_map.insert(Point2D { x: x, y: y }, MapType::Rock);
- }
- }
- }
- }
- sand_map
- }
- fn solve(input: &str) -> io::Result<()> {
- let file = File::open(input).expect("Input file not found.");
- let reader = BufReader::new(file);
- // Input
- let input: Vec<String> = match reader.lines().collect() {
- Err(err) => panic!("Unknown error reading input: {}", err),
- Ok(result) => result,
- };
- // Part 1
- let mut sand_map = build_map(&input);
- // Identify the extent of the abyss
- let abyss = &sand_map.keys().map(|&pt| pt.y).max().unwrap() + 2;
- // Simulate sand
- 'sand_lp: for sand in 0.. {
- let result = drop_sand(&mut sand_map,abyss,true);
- if !result { println!("Part 1: {sand}"); break 'sand_lp; } // 1061
- }
- // Part 2 (reset map)
- let mut sand_map = build_map(&input);
- // Build floor
- for x in 0..=1000 {
- sand_map.insert(Point2D { x: x, y: abyss },MapType::Rock);
- }
- 'sand_lp2: for sand in 1.. {
- let result = drop_sand(&mut sand_map,abyss,false);
- if !result { println!("Part 2: {sand}"); break 'sand_lp2; } // 25055
- }
- Ok(())
- }
- fn main() {
- let args: Vec<String> = env::args().collect();
- let filename = &args[1];
- solve(&filename).unwrap();
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement