#![feature(iter_map_windows)] //! Half of the puzzle seems like a fancy way to say that the puzzle corners have to be within any //! other rectangle or adyacent (as in same x or y as any other point) to other corners. //! //! I think even adyacent is within the "other rectangle thing", because use std::ops::Range; #[unsafe(no_mangle)] pub extern "Rust" fn challenge_usize(buf: &[u8]) -> usize { let coords = buf[..(buf.len() - 1)] .split(|&b| b == b'\n') .map(parse_ln) .collect::>(); // assuming each coord is contiguous to the prev one let mut edges = coords .iter() .cloned() .chain([coords[0]]) .map_windows(|&[a, b]| (a, b)) .collect::>(); edges.sort_by(|(a1, a2), (b1, b2)| { (a1.0.abs_diff(a2.0) + a1.1.abs_diff(a2.1)) .cmp(&(b1.0.abs_diff(b2.0) + b1.1.abs_diff(b2.1))) }); let mut max_area = 0; for (i, coor1) in coords.iter().enumerate() { for coor2 in coords.iter().skip(i) { let dx = coor1.0.abs_diff(coor2.0) + 1; let dy = coor1.1.abs_diff(coor2.1) + 1; let area = dx * dy; if is_really_contained((*coor1, *coor2), &edges) { max_area = max_area.max(area); } } } max_area } /// If any bouding vertex is well within (not sitting on a rectangle's edge), the rectangle is not /// well contained fn is_really_contained( (rect0, rect1): ((usize, usize), (usize, usize)), edges: &[((usize, usize), (usize, usize))], ) -> bool { let (rect0, rect1) = ( (rect0.0.min(rect1.0), rect0.1.min(rect1.1)), (rect0.0.max(rect1.0), rect0.1.max(rect1.1)), ); let xran = (rect0.0 + 1)..(rect1.0); let yran = (rect0.1 + 1)..(rect1.1); // Optimization, no need to check each range's point for (edge1, edge2) in edges { if edge1.0 == edge2.0 && xran.contains(&edge1.0) && rangeoverlap(&mkrange(edge1.1, edge2.1), &yran) { return false; } if edge1.1 == edge2.1 && yran.contains(&edge1.1) && rangeoverlap(&mkrange(edge1.0, edge2.0), &xran) { return false; } } true } fn mkrange(a: T, b: T) -> Range { a.min(b)..a.max(b) } fn rangeoverlap(a: &Range, b: &Range) -> bool { if a.end <= b.start { return false; } if a.start >= b.end { return false; } true } fn parse_ln(ln: &[u8]) -> (usize, usize) { let mut iter = ln.split(|&b| b == b',').map(|slice| { slice .iter() .fold(0, |acc, b| acc * 10 + (b - b'0') as usize) }); (iter.next().unwrap(), iter.next().unwrap()) }