Advertisement
Guest User

AOC 2018 Day 17 part1 attempt

a guest
Dec 29th, 2018
92
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Rust 7.84 KB | None | 0 0
  1. use std::collections::HashSet;
  2. use std::fs;
  3.  
  4. use regex::Regex;
  5.  
  6. fn main() {
  7.     let mut ug = Underground::from_file("input-dev2.txt");
  8. //    println!("Boundaries: {:?}", ug.boundaries);
  9.     ug.water_stream(&Point::from(500, 0));
  10.     ug.show();
  11.  
  12.     println!();
  13.     println!("Water path size: {}", ug.water_path.len());
  14.     println!("Water path len: {}", ug.water_path_len);
  15. }
  16.  
  17. struct Underground {
  18.     boundaries: Boundaries,
  19.     clays: HashSet<Point>,
  20.     water_path: HashSet<Point>,
  21.     water_path_len: i32,
  22.     steady_water: HashSet<Point>,
  23. }
  24.  
  25. impl Underground {
  26.  
  27.     fn water_stream(&mut self, start: &Point) {
  28.         use crate::HorizontalScanResult::*;
  29.        
  30.         let mut y = start.y;
  31.         loop {
  32.             let p = Point::from(start.x, y);
  33.             let p_down = Point::from(start.x, y+1);
  34.  
  35.             if y >= self.boundaries.y_min && y <= self.boundaries.y_max {
  36.                 self.water_path.insert(p);
  37.                 self.water_path_len += 1;
  38.             }
  39.  
  40.             if self.is_stable_cell(&p_down) {
  41. //                println!("Stopping @ {:?}", p);
  42.                 let (left_scan_result, right_scan_result) = self.horizontal_scan(&p);
  43.  
  44.                 match (left_scan_result, right_scan_result) {
  45.                     (Wall(p1), Wall(p2)) => {
  46.                         self.add_range_to_steady(&p1, &p2);
  47.                         self.add_range_to_water_path(&p1, &p2);
  48.                         y -= 1;
  49.                     },
  50.                     (Fall(p1), Wall(p2)) => {
  51.                         self.add_range_to_water_path(&p1, &p2);
  52.                         self.water_stream(&p1);
  53.                         break;
  54.                     },
  55.                     (Wall(p1), Fall(p2)) => {
  56.                         self.add_range_to_water_path(&p1, &p2);
  57.                         self.water_stream(&p2);
  58.                         break;
  59.                     },
  60.                     (Fall(p1), Fall(p2)) => {
  61.                         self.add_range_to_water_path(&p1, &p2);
  62.                         self.water_stream(&p1);
  63.                         self.water_stream(&p2);
  64.                         break;
  65.                     },
  66.                 }
  67.             } else {
  68.                 y += 1;
  69.                 if y > self.boundaries.y_max {
  70.                     break;
  71.                 }
  72.             }
  73.         }
  74.     }
  75.  
  76.     fn horizontal_scan(&mut self, start: &Point) -> (HorizontalScanResult, HorizontalScanResult) {
  77.         // to the left, to the left
  78.         let mut x = start.x;
  79.         let left_scan_result = loop {
  80.             let p = Point::from(x, start.y);
  81.  
  82.             let p_left = Point::from(x - 1, start.y);
  83.             let p_down = Point::from(x, start.y+1);
  84.  
  85.             if !self.is_stable_cell(&p_down) {
  86. //                println!("Stopping left scan (Fall) @ {:?}", p);
  87.                 break HorizontalScanResult::Fall(p);
  88.             }
  89.  
  90.             if self.clays.contains(&p_left) {
  91. //                println!("Stopping left scan (Wall) @ {:?}", p);
  92.                 break HorizontalScanResult::Wall(p);
  93.             }
  94.  
  95.             x -= 1;
  96.         };
  97.  
  98.         // to the right, to the right
  99.         x = start.x;
  100.         let right_scan_result = loop {
  101.             let p = Point::from(x, start.y);
  102.  
  103.             let p_right = Point::from(x + 1, start.y);
  104.             let p_down = Point::from(x, start.y+1);
  105.  
  106.             if !self.is_stable_cell(&p_down) {
  107. //                println!("Stopping right scan (Fall) @ {:?}", p);
  108.                 break HorizontalScanResult::Fall(p);
  109.             }
  110.  
  111.             if self.clays.contains(&p_right) {
  112. //                println!("Stopping right scan (Wall) @ {:?}", p);
  113.                 break HorizontalScanResult::Wall(p);
  114.             }
  115.  
  116.             x += 1;
  117.         };
  118.  
  119.         (left_scan_result, right_scan_result)
  120.     }
  121.  
  122.     fn add_range_to_steady(&mut self, start: &Point, end_inclusive: &Point) {
  123.         let y = start.y;
  124.         for x in start.x..=end_inclusive.x {
  125.             self.steady_water.insert(Point::from(x, y));
  126.         }
  127.     }
  128.  
  129.     fn add_range_to_water_path(&mut self, start: &Point, end_inclusive: &Point) {
  130.         let y = start.y;
  131.         if y >= self.boundaries.y_min && y <= self.boundaries.y_max {
  132.             for x in start.x..=end_inclusive.x {
  133.                 self.water_path.insert(Point::from(x, y));
  134.             }
  135.             self.water_path_len += end_inclusive.x - start.x + 1;
  136.         }
  137.     }
  138.  
  139.     fn is_stable_cell(&self, p: &Point) -> bool {
  140.         self.clays.contains(p) || self.steady_water.contains(p)
  141.     }
  142.  
  143.     fn show(&self) {
  144.         let b = self.boundaries;
  145.         println!("    {}", b.x_min-1);
  146.         for y in b.y_min-2..=b.y_max+2 {
  147.             print!("{:4} ", y);
  148.             for x in b.x_min-1..=b.x_max+1 {
  149.                 let p = Point::from(x, y);
  150.                 if self.clays.contains(&p) {
  151.                     print!("#");
  152.                 } else if self.steady_water.contains(&p) {
  153.                     print!("~");
  154.                 } else if self.water_path.contains(&p) {
  155.                     print!("|");
  156.                 } else {
  157.                     print!(".")
  158.                 }
  159.             }
  160.             println!();
  161.         }
  162.     }
  163.  
  164.     fn from_file(filename: &str) -> Underground {
  165.         let contents = fs::read_to_string(filename).unwrap();
  166.         let lines = contents.lines();
  167.  
  168.         let mut clays = HashSet::new();
  169.         let mut boundaries = Boundaries {
  170.             x_min: i32::max_value(),
  171.             x_max: i32::min_value(),
  172.             y_min: i32::max_value(),
  173.             y_max: i32::min_value(),
  174.         };
  175.  
  176.         let horizontal_re = Regex::new(r"y=(\d+), x=(\d+)..(\d+)").unwrap();
  177.         let vertical_re = Regex::new(r"x=(\d+), y=(\d+)..(\d+)").unwrap();
  178.  
  179.         for line in lines {
  180.             if horizontal_re.is_match(line) {
  181.                 let numbers = parse_captures(&horizontal_re, line);
  182.                 let y = numbers[0];
  183.                 for x in numbers[1]..=numbers[2] {
  184.                     clays.insert(Point::from(x, y));
  185.                 }
  186.                 boundaries.y_min = boundaries.y_min.min(y);
  187.                 boundaries.y_max = boundaries.y_max.max(y);
  188.                 boundaries.x_min = boundaries.x_min.min(numbers[1]);
  189.                 boundaries.x_max = boundaries.x_max.max(numbers[2]);
  190.             } else if vertical_re.is_match(line) {
  191.                 let numbers = parse_captures(&vertical_re, line);
  192.                 let x = numbers[0];
  193.                 for y in numbers[1]..=numbers[2] {
  194.                     clays.insert(Point::from(x, y));
  195.                 }
  196.                 boundaries.y_min = boundaries.y_min.min(numbers[1]);
  197.                 boundaries.y_max = boundaries.y_max.max(numbers[2]);
  198.                 boundaries.x_min = boundaries.x_min.min(x);
  199.                 boundaries.x_max = boundaries.x_max.max(x);
  200.             } else {
  201.                 panic!(format!("Unexpected input line '{}'", line));
  202.             }
  203.         }
  204.  
  205.         Underground {
  206.             clays,
  207.             boundaries,
  208.             water_path: HashSet::new(),
  209.             steady_water: HashSet::new(),
  210.             water_path_len: 0,
  211.         }
  212.     }
  213.  
  214. }
  215.  
  216. enum HorizontalScanResult {
  217.     Wall(Point),
  218.     Fall(Point),
  219. }
  220.  
  221. #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
  222. struct Boundaries {
  223.     x_min: i32,
  224.     x_max: i32,
  225.     y_min: i32,
  226.     y_max: i32,
  227. }
  228.  
  229. #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
  230. struct Point {
  231.     x: i32,
  232.     y: i32,
  233. }
  234.  
  235. impl Point {
  236.  
  237.     fn from(x: i32, y: i32) -> Point {
  238.         Point { x, y }
  239.     }
  240.  
  241. }
  242.  
  243. fn parse_captures(re: &Regex, text: &str) -> Vec<i32> {
  244.     let captures = re.captures_iter(text).nth(0).unwrap();
  245.     let mut result = Vec::new();
  246.     result.push(captures[1].parse().unwrap());
  247.     result.push(captures[2].parse().unwrap());
  248.     result.push(captures[3].parse().unwrap());
  249.     result
  250. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement