Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- use std::collections::HashSet;
- use std::fs;
- use regex::Regex;
- fn main() {
- let mut ug = Underground::from_file("input-dev2.txt");
- // println!("Boundaries: {:?}", ug.boundaries);
- ug.water_stream(&Point::from(500, 0));
- ug.show();
- println!();
- println!("Water path size: {}", ug.water_path.len());
- println!("Water path len: {}", ug.water_path_len);
- }
- struct Underground {
- boundaries: Boundaries,
- clays: HashSet<Point>,
- water_path: HashSet<Point>,
- water_path_len: i32,
- steady_water: HashSet<Point>,
- }
- impl Underground {
- fn water_stream(&mut self, start: &Point) {
- use crate::HorizontalScanResult::*;
- let mut y = start.y;
- loop {
- let p = Point::from(start.x, y);
- let p_down = Point::from(start.x, y+1);
- if y >= self.boundaries.y_min && y <= self.boundaries.y_max {
- self.water_path.insert(p);
- self.water_path_len += 1;
- }
- if self.is_stable_cell(&p_down) {
- // println!("Stopping @ {:?}", p);
- let (left_scan_result, right_scan_result) = self.horizontal_scan(&p);
- match (left_scan_result, right_scan_result) {
- (Wall(p1), Wall(p2)) => {
- self.add_range_to_steady(&p1, &p2);
- self.add_range_to_water_path(&p1, &p2);
- y -= 1;
- },
- (Fall(p1), Wall(p2)) => {
- self.add_range_to_water_path(&p1, &p2);
- self.water_stream(&p1);
- break;
- },
- (Wall(p1), Fall(p2)) => {
- self.add_range_to_water_path(&p1, &p2);
- self.water_stream(&p2);
- break;
- },
- (Fall(p1), Fall(p2)) => {
- self.add_range_to_water_path(&p1, &p2);
- self.water_stream(&p1);
- self.water_stream(&p2);
- break;
- },
- }
- } else {
- y += 1;
- if y > self.boundaries.y_max {
- break;
- }
- }
- }
- }
- fn horizontal_scan(&mut self, start: &Point) -> (HorizontalScanResult, HorizontalScanResult) {
- // to the left, to the left
- let mut x = start.x;
- let left_scan_result = loop {
- let p = Point::from(x, start.y);
- let p_left = Point::from(x - 1, start.y);
- let p_down = Point::from(x, start.y+1);
- if !self.is_stable_cell(&p_down) {
- // println!("Stopping left scan (Fall) @ {:?}", p);
- break HorizontalScanResult::Fall(p);
- }
- if self.clays.contains(&p_left) {
- // println!("Stopping left scan (Wall) @ {:?}", p);
- break HorizontalScanResult::Wall(p);
- }
- x -= 1;
- };
- // to the right, to the right
- x = start.x;
- let right_scan_result = loop {
- let p = Point::from(x, start.y);
- let p_right = Point::from(x + 1, start.y);
- let p_down = Point::from(x, start.y+1);
- if !self.is_stable_cell(&p_down) {
- // println!("Stopping right scan (Fall) @ {:?}", p);
- break HorizontalScanResult::Fall(p);
- }
- if self.clays.contains(&p_right) {
- // println!("Stopping right scan (Wall) @ {:?}", p);
- break HorizontalScanResult::Wall(p);
- }
- x += 1;
- };
- (left_scan_result, right_scan_result)
- }
- fn add_range_to_steady(&mut self, start: &Point, end_inclusive: &Point) {
- let y = start.y;
- for x in start.x..=end_inclusive.x {
- self.steady_water.insert(Point::from(x, y));
- }
- }
- fn add_range_to_water_path(&mut self, start: &Point, end_inclusive: &Point) {
- let y = start.y;
- if y >= self.boundaries.y_min && y <= self.boundaries.y_max {
- for x in start.x..=end_inclusive.x {
- self.water_path.insert(Point::from(x, y));
- }
- self.water_path_len += end_inclusive.x - start.x + 1;
- }
- }
- fn is_stable_cell(&self, p: &Point) -> bool {
- self.clays.contains(p) || self.steady_water.contains(p)
- }
- fn show(&self) {
- let b = self.boundaries;
- println!(" {}", b.x_min-1);
- for y in b.y_min-2..=b.y_max+2 {
- print!("{:4} ", y);
- for x in b.x_min-1..=b.x_max+1 {
- let p = Point::from(x, y);
- if self.clays.contains(&p) {
- print!("#");
- } else if self.steady_water.contains(&p) {
- print!("~");
- } else if self.water_path.contains(&p) {
- print!("|");
- } else {
- print!(".")
- }
- }
- println!();
- }
- }
- fn from_file(filename: &str) -> Underground {
- let contents = fs::read_to_string(filename).unwrap();
- let lines = contents.lines();
- let mut clays = HashSet::new();
- let mut boundaries = Boundaries {
- x_min: i32::max_value(),
- x_max: i32::min_value(),
- y_min: i32::max_value(),
- y_max: i32::min_value(),
- };
- let horizontal_re = Regex::new(r"y=(\d+), x=(\d+)..(\d+)").unwrap();
- let vertical_re = Regex::new(r"x=(\d+), y=(\d+)..(\d+)").unwrap();
- for line in lines {
- if horizontal_re.is_match(line) {
- let numbers = parse_captures(&horizontal_re, line);
- let y = numbers[0];
- for x in numbers[1]..=numbers[2] {
- clays.insert(Point::from(x, y));
- }
- boundaries.y_min = boundaries.y_min.min(y);
- boundaries.y_max = boundaries.y_max.max(y);
- boundaries.x_min = boundaries.x_min.min(numbers[1]);
- boundaries.x_max = boundaries.x_max.max(numbers[2]);
- } else if vertical_re.is_match(line) {
- let numbers = parse_captures(&vertical_re, line);
- let x = numbers[0];
- for y in numbers[1]..=numbers[2] {
- clays.insert(Point::from(x, y));
- }
- boundaries.y_min = boundaries.y_min.min(numbers[1]);
- boundaries.y_max = boundaries.y_max.max(numbers[2]);
- boundaries.x_min = boundaries.x_min.min(x);
- boundaries.x_max = boundaries.x_max.max(x);
- } else {
- panic!(format!("Unexpected input line '{}'", line));
- }
- }
- Underground {
- clays,
- boundaries,
- water_path: HashSet::new(),
- steady_water: HashSet::new(),
- water_path_len: 0,
- }
- }
- }
- enum HorizontalScanResult {
- Wall(Point),
- Fall(Point),
- }
- #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
- struct Boundaries {
- x_min: i32,
- x_max: i32,
- y_min: i32,
- y_max: i32,
- }
- #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)]
- struct Point {
- x: i32,
- y: i32,
- }
- impl Point {
- fn from(x: i32, y: i32) -> Point {
- Point { x, y }
- }
- }
- fn parse_captures(re: &Regex, text: &str) -> Vec<i32> {
- let captures = re.captures_iter(text).nth(0).unwrap();
- let mut result = Vec::new();
- result.push(captures[1].parse().unwrap());
- result.push(captures[2].parse().unwrap());
- result.push(captures[3].parse().unwrap());
- result
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement