use std::fs; use std::path::Path; use regex::Regex; use lazy_static::lazy_static; #[derive(Debug,PartialEq)] struct Segment(u32,u32,u32,u32); impl Segment { fn is_hor(&self) -> bool { self.1 == self.3 } fn is_ver(&self) -> bool { self.0 == self.2 } } /* AOC21 Day 7: https://adventofcode.com/2021/day/7 */ fn main() { let input = Path::new("resources").join("input.txt"); let content = fs::read_to_string(input).expect("Unable to read input file"); let (size, segments) = parse_input(&content); let area = radar(&segments, size, false); println!("Ex1: The result is: {}", area.iter().filter(|&&c| c > 1).count()); let area = radar(&segments, size, true); println!("Ex2: The result is: {}", area.iter().filter(|&&c| c > 1).count()); } fn radar(segments: &[Segment], size: u32, diagonals: bool) -> Vec { let mut area = vec![0;(size+1).pow(2) as usize]; segments.iter().for_each( |s| match s { s if s.is_hor() => { range(s.0, s.2).iter().for_each(|x| area[((size+1)*s.1 + x) as usize] += 1) }, s if s.is_ver() => { range(s.1, s.3).iter().for_each(|y| area[((size+1)*y + s.0) as usize] += 1) }, s => { if diagonals { range(s.0,s.2).iter().zip(range(s.1,s.3)).for_each(|(x,y)| area[((size+1)*y + x) as usize] += 1) } } } ); area } fn parse_input(s: &str) -> (u32, Vec) { lazy_static! { static ref RE: Regex = Regex::new(r"^(\d+),(\d+) -> (\d+),(\d+)$").unwrap(); } let mut max = 0; let segs = s.lines().map(|l| { let caps = RE.captures(l).expect("Malformed input"); let x1 = caps.get(1).unwrap().as_str().parse().expect("Malformed input"); let y1 = caps.get(2).unwrap().as_str().parse().expect("Malformed input"); let x2 = caps.get(3).unwrap().as_str().parse().expect("Malformed input"); let y2 = caps.get(4).unwrap().as_str().parse().expect("Malformed input"); max = *[x1, x2, y1, y2, max].iter().max().unwrap(); Segment(x1, y1, x2, y2) }).collect(); (max, segs) } fn range(from: u32, to: u32) -> Vec { if from < to { (from..=to).collect() } else { (to..=from).rev().collect() } } #[cfg(test)] mod tests { use super::*; const INPUT: &str = "0,9 -> 5,9 8,0 -> 0,8 9,4 -> 3,4 2,2 -> 2,1 7,0 -> 7,4 6,4 -> 2,0 0,9 -> 2,9 3,4 -> 1,4 0,0 -> 8,8 5,5 -> 8,2"; #[test] fn input_parsing() { let (size, segments) = parse_input(INPUT); assert_eq!(9,size); assert_eq!(vec![ Segment(0,9,5,9), Segment(8,0,0,8), Segment(9,4,3,4), Segment(2,2,2,1), Segment(7,0,7,4), Segment(6,4,2,0), Segment(0,9,2,9), Segment(3,4,1,4), Segment(0,0,8,8), Segment(5,5,8,2), ],segments); } #[test] fn examples() { let (size, segments) = parse_input(INPUT); assert_eq!(vec![ 0,0,0,0,0,0,0,1,0,0, 0,0,1,0,0,0,0,1,0,0, 0,0,1,0,0,0,0,1,0,0, 0,0,0,0,0,0,0,1,0,0, 0,1,1,2,1,1,1,2,1,1, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0, 2,2,2,1,1,1,0,0,0,0 ], radar(&segments, size, false)); assert_eq!(vec![ 1,0,1,0,0,0,0,1,1,0, 0,1,1,1,0,0,0,2,0,0, 0,0,2,0,1,0,1,1,1,0, 0,0,0,1,0,2,0,2,0,0, 0,1,1,2,3,1,3,2,1,1, 0,0,0,1,0,2,0,0,0,0, 0,0,1,0,0,0,1,0,0,0, 0,1,0,0,0,0,0,1,0,0, 1,0,0,0,0,0,0,0,1,0, 2,2,2,1,1,1,0,0,0,0 ], radar(&segments, size, true)) } }