extern crate advent_of_code_2018; use advent_of_code_2018::*; use std::error::Error; use std::path::PathBuf; // cargo watch -cs "cargo run --release --bin day_17" struct CoordBuilder { xmin: Option, xmax: Option, ymin: Option, ymax: Option } #[derive(Debug)] struct Coord { xmin: usize, xmax: usize, ymin: usize, ymax: usize } impl CoordBuilder { fn new() -> CoordBuilder { CoordBuilder { xmin: None, xmax: None, ymin: None, ymax: None } } fn build(&self) -> Coord { Coord { xmin: self.xmin.unwrap(), xmax: self.xmax.unwrap(), ymin: self.ymin.unwrap(), ymax: self.ymax.unwrap(), } } } #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum Tile { Clay, RunningWater, HalfSettledWater, SettledWater, Sand } fn main() -> Result<(), Box> { let input = read_file(&PathBuf::from("inputs/17.txt"))?; let clay_coords = input.iter().map(|line| { let mut builder = CoordBuilder::new(); for split in line.split(", ") { if split.starts_with("x=") { let mut range_split = split .trim_matches(|c: char| !c.is_numeric()) .split("..") .map(|s| s.parse().unwrap()); if let Some(min) = range_split.next() { builder.xmin = Some(min); builder.xmax = Some(min+1); } if let Some(max) = range_split.next() { builder.xmax = Some(max+1); } } else { let mut range_split = split .trim_matches(|c: char| !c.is_numeric()) .split("..") .map(|s| s.parse().unwrap()); if let Some(min) = range_split.next() { builder.ymin = Some(min); builder.ymax = Some(min+1); } if let Some(max) = range_split.next() { builder.ymax = Some(max+1); } } } builder.build() }).collect::>(); let range = CoordinateSystem { xmin: clay_coords.iter().min_by_key(|coord| coord.xmin).unwrap().xmin-2, xmax: clay_coords.iter().max_by_key(|coord| coord.xmax).unwrap().xmax+2, ymin: clay_coords.iter().min_by_key(|coord| coord.ymin).unwrap().ymin, ymax: clay_coords.iter().max_by_key(|coord| coord.ymax).unwrap().ymax }; debug!(range); let mut map = vec!(Tile::Sand; range.vector_size()); for coord in clay_coords { for y in coord.ymin..coord.ymax { for x in coord.xmin..coord.xmax { map[range.to_vec(x, y)] = Tile::Clay; } } } debug!(map[range.to_vec(500, range.ymin)]); map[range.to_vec(500, range.ymin)] = Tile::RunningWater; let mut last_iter = Vec::new(); while last_iter != map { last_iter = map.clone(); for y in range.ymin..range.ymax-1 { for x in range.xmin..range.xmax { match map[range.to_vec(x, y)] { Tile::RunningWater => { if map[range.to_vec(x, y+1)] == Tile::Sand { map[range.to_vec(x, y+1)] = Tile::RunningWater; } if map[range.to_vec(x-1, y)] == Tile::Sand && (map[range.to_vec(x, y+1)] == Tile::Clay || map[range.to_vec(x, y+1)] == Tile::SettledWater) { map[range.to_vec(x-1, y)] = Tile::RunningWater; } if map[range.to_vec(x+1, y)] == Tile::Sand && (map[range.to_vec(x, y+1)] == Tile::Clay || map[range.to_vec(x, y+1)] == Tile::SettledWater) { map[range.to_vec(x+1, y)] = Tile::RunningWater; } if (map[range.to_vec(x-1, y)] == Tile::Clay || map[range.to_vec(x-1, y)] == Tile::HalfSettledWater) && (map[range.to_vec(x, y+1)] == Tile::Clay || map[range.to_vec(x, y+1)] == Tile::SettledWater) { map[range.to_vec(x, y)] = Tile::HalfSettledWater; } }, Tile::HalfSettledWater => { if map[range.to_vec(x+1, y)] == Tile::Clay { for xleft in 0.. { if map[range.to_vec(x-xleft, y)] == Tile::HalfSettledWater { map[range.to_vec(x-xleft, y)] = Tile::SettledWater; } else { break; } } } }, _ => {} } } } } let water_tiles = map.iter() .filter(|&&t| t == Tile::RunningWater || t == Tile::SettledWater || t == Tile::HalfSettledWater) .count(); debug!(water_tiles); let settled_water_tiles = map.iter() .filter(|&&t| t == Tile::SettledWater) .count(); debug!(settled_water_tiles); Ok(()) } #[derive(Debug)] struct CoordinateSystem { xmin: usize, xmax: usize, ymin: usize, ymax: usize } impl CoordinateSystem { fn vector_size(&self) -> usize { (self.xmax - self.xmin) * (self.ymax - self.ymin) } fn to_vec(&self, x: usize, y: usize) -> usize { ((y - self.ymin) * (self.xmax - self.xmin)) + (x - self.xmin) } }