use crate::city; use crate::city::{City, House, SIZE, HOUSE_RANGE}; use itertools::Itertools; use std::collections::VecDeque; pub fn try_combine(city: &City, layout1: &Vec, layout2: &Vec) { // Sorted in reverse so we can remove from the end let mut houses1_sorted: Vec = layout1.iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect(); let mut houses2_sorted: Vec = layout2.iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect(); // TODO: We may want to maintain K left sides and K right sides to compare K^2 layouts at once at each x // houses1 is left, houses2 is right let mut left = LeftLine::new(); let mut right = RightLine::new(); // Make sure that we include all houses initially while let Some(house) = houses2_sorted.pop() { right.add_house(house); } // x is the last left coordinate, x+1 is right for x in 0..SIZE { // Update the lines while let Some(house) = houses1_sorted.last() { if house.x == x { left.add_house(*house); houses1_sorted.pop(); } else { break; } } right.remove_houses(x); // Check compatibility of lines if x == 0 { // Cannot check this due to limitations in the implementation of LeftLine, // it wouldn't be very interesting anyway. continue; } if is_compatible(city, &left, &right) { eprintln!("Compatible on X {}", x); let houses: Vec<_> = layout1.iter().filter(|h| h.x <= x).chain(layout2.iter().filter(|h| h.x > x)).map(|h| *h).collect(); eprintln!("Price {}", city::get_price(&city, &houses)); //if let Some(price) = city::is_valid(&city, &houses) { // eprintln!("Merge valid with price {}", price) //} else { // eprintln!("Merge actually invalid, printing invalid merge"); // println!("{}", houses.len()); // for house in houses { // println!("{} {}", house.y, house.x); // } //} } else { eprintln!("Incompatible on X {}", x); } } } fn is_compatible(city: &City, left: &LeftLine, right: &RightLine) -> bool { for y in 0..SIZE { let max_left_covered_x = left.get_max_covered_x(y); let min_right_covered_x = right.get_min_covered_x(y); // This range will often be empty for x in (max_left_covered_x+1)..min_right_covered_x { if city.is_house_xy(x, y) { // This is an uncovered house eprintln!("House ({},{}) in uncovered range [{},{}]", x, y, max_left_covered_x+1, min_right_covered_x-1); return false; } } } true } struct LeftLine { covers: Vec } struct RightLine { covers: Vec, houses: VecDeque } impl LeftLine { pub fn new() -> Self { // XXX: Careful, default of 0 includes covering first vertical line let covers = vec![0; SIZE]; LeftLine {covers} } pub fn add_house(&mut self, house: House) { let range_rect = house.range_rectangle(); for y in range_rect.top..=range_rect.bottom { // Should always be the max variant self.covers[y] = self.covers[y].max(range_rect.right); } } pub fn get_max_covered_x(&self, y: usize) -> usize { self.covers[y] } } impl RightLine { pub fn new() -> Self { let covers = vec![usize::MAX; SIZE]; let houses = VecDeque::new(); RightLine {covers, houses} } pub fn add_house(&mut self, house: House) { // Added houses have to always be ordered by x eprintln!("Added house ({},{}) to right line", house.x, house.y); let range_rect = house.range_rectangle(); for y in range_rect.top..=range_rect.bottom { self.covers[y] = self.covers[y].min(range_rect.left); } self.houses.push_back(house); } pub fn remove_houses(&mut self, x: usize) { // Has to be called with x, x+1, x+2... while let Some(house) = self.houses.front() { if house.x == x { let removed_house = self.houses.pop_front().unwrap(); let removed_rect = removed_house.range_rectangle(); // Remove the now-outdated distances around the removed house for y in removed_rect.top..=removed_rect.bottom { self.covers[y] = usize::MAX; } // Update distances around the removed house if the area of any houses // intersects the removed area for house in &self.houses { let house_rect = house.range_rectangle(); // TODO: Verify this intersection is correct let y_intersection = if removed_house.y < house.y { house_rect.top..=removed_rect.bottom } else { removed_rect.top..=house_rect.bottom }; for y in y_intersection { self.covers[y] = self.covers[y].min(house_rect.left); } } } else { break; } } } pub fn get_min_covered_x(&self, y: usize) -> usize { self.covers[y].min(SIZE) } }