use std::{cmp::Ordering, collections::BTreeMap, fs::read_to_string}; use itertools::Itertools; fn main() { let coords: Vec<_> = read_to_string("../input.txt") .expect("failed to open input file") .lines() .map(|line| { let (x, y) = line.split_once(',').expect("failed to parse co-ordinate"); ( x.parse::().expect("failed to parse x"), y.parse::().expect("failed to parse y"), ) }) .collect(); let mut horizontal_edges: BTreeMap<_, Vec<_>> = BTreeMap::new(); let mut vertical_edges: BTreeMap<_, Vec<_>> = BTreeMap::new(); for ((from_x, from_y), (to_x, to_y)) in coords.iter().circular_tuple_windows() { if from_x == to_x { vertical_edges .entry(*from_x) .or_default() .push(if from_y < to_y { from_y + 1..*to_y } else { to_y + 1..*from_y }); } else { horizontal_edges .entry(*from_y) .or_default() .push(if from_x < to_x { from_x + 1..*to_x } else { to_x + 1..*from_x }); } } let largest_area = coords .into_iter() .tuple_combinations() .filter(|&((from_x, from_y), (to_x, to_y))| { let x_range = match from_x.cmp(&to_x) { Ordering::Equal => from_x..from_x + 1, Ordering::Less => from_x + 1..to_x, Ordering::Greater => to_x + 1..from_x, }; let y_range = match from_y.cmp(&to_y) { Ordering::Equal => from_y..from_y + 1, Ordering::Less => from_y + 1..to_y, Ordering::Greater => to_y + 1..from_y, }; vertical_edges.range(x_range.clone()).all(|(_, columns)| { columns .iter() .all(|column| column.start > y_range.end || column.end < y_range.start) }) && horizontal_edges.range(y_range).all(|(_, rows)| { rows.iter() .all(|row| row.start > x_range.end || row.end < x_range.start) }) }) .map(|((from_x, from_y), (to_x, to_y))| { (from_x.abs_diff(to_x) + 1) * (from_y.abs_diff(to_y) + 1) }) .max() .expect("input file was empty"); println!("The largest rectangular area you can make is {largest_area}!"); }