use std::collections::HashSet; use std::env; use std::fs::File; use std::io::{BufRead, BufReader}; #[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)] struct Point { x: usize, y: usize, height: u32, } #[derive(Debug, Clone, PartialEq, Eq)] struct Basin { points: HashSet, } fn main() { let reader = open_file(); let mut points: Vec> = Vec::new(); let mut basins: Vec = Vec::new(); for line in reader.lines() { points.push( line.unwrap() .trim() .chars() .map(|x| x.to_digit(10).unwrap()) .collect(), ); } let nine = vec![9]; let mut risk_level: u32 = 0; for (idx, height) in points.iter().enumerate() { for (ndx, num) in height.iter().enumerate() { let up = points .get(((idx as isize) - 1) as usize) .unwrap_or(&nine) .get(ndx) .unwrap_or(&9); let down = points .get(idx + 1) .unwrap_or_else(|| &nine) .get(ndx) .unwrap_or_else(|| &9); let left = height .get((ndx as isize - 1) as usize) .unwrap_or_else(|| &9); let right = height .get((ndx as isize + 1) as usize) .unwrap_or_else(|| &9); if num < up && num < down && num < right && num < left { risk_level += 1 + *num; basins.push(Basin { points: HashSet::from_iter(vec![Point { x: idx, y: ndx, height: *num, }]), }); } } } // TODO: fix this maybe because i hate it <20-12-21, yigit> // for basin in basins.iter_mut() { let mut stack: Vec = Vec::new(); stack.extend(basin.points.clone().into_iter()); while !stack.is_empty() { let minibasin = stack.pop().unwrap(); let up = points .get(((minibasin.x as isize) - 1) as usize) .unwrap_or(&nine) .get(minibasin.y) .unwrap_or(&9); let down = match points.get(minibasin.x + 1) { Some(line) => line.get(minibasin.y).unwrap_or(&9), None => &9, }; let left = match points.get(minibasin.x) { Some(line) => line .get(((minibasin.y as isize) - 1) as usize) .unwrap_or(&9), None => &9, }; let right = match points.get(minibasin.x) { Some(line) => line.get(minibasin.y + 1).unwrap_or(&9), None => &9, }; if up != &9 { let p = Point { x: minibasin.x - 1, y: minibasin.y, height: *up, }; if !basin.points.contains(&p) { stack.push(p); basin.points.insert(p); } } if down != &9 { let p = Point { x: minibasin.x + 1, y: minibasin.y, height: *down, }; if !basin.points.contains(&p) { stack.push(p); basin.points.insert(p); } } if left != &9 { let p = Point { x: minibasin.x, y: minibasin.y - 1, height: *left, }; if !basin.points.contains(&p) { stack.push(p); basin.points.insert(p); } } if right != &9 { let p = Point { x: minibasin.x, y: minibasin.y + 1, height: *right, }; if !basin.points.contains(&p) { stack.push(p); basin.points.insert(p); } } } } let mut lens: Vec = basins.iter().map(|x| x.points.len()).collect(); lens.sort_unstable(); lens.reverse(); let biggest_basins: usize = lens.iter().take(3).product(); println!("{}", biggest_basins); println!("{}", risk_level); } fn open_file() -> BufReader { let args: Vec = env::args().collect(); if args.len() != 2 { eprintln!("Usage: {} ", args[0]); std::process::exit(1); } let filename = &args[1]; let file = File::open(filename).unwrap_or_else(|_| panic!("No such file: {}", filename)); BufReader::new(file) }