Browse Source

Vertical combines

master
Jirka Sejkora 4 years ago
parent
commit
751e0d81ff
  1. 15
      src/combine-layouts.rs
  2. 124
      src/combine.rs

15
src/combine-layouts.rs

@ -15,14 +15,11 @@ fn main() {
let layouts = db.layouts(); let layouts = db.layouts();
let sorted: Vec<_> = layouts.iter().sorted_by(|x, y| city::get_price(&city, x.houses()).cmp(&city::get_price(&city, y.houses()))).collect(); let sorted: Vec<_> = layouts.iter().sorted_by(|x, y| city::get_price(&city, x.houses()).cmp(&city::get_price(&city, y.houses()))).collect();
let first = sorted[1];
let second = sorted[0];
eprintln!("Combining layouts (ID {}, price {}) and (ID {}, price {})",
first.id(),
city::get_price(&city, first.houses()),
second.id(),
city::get_price(&city, second.houses()),
);
combine::try_combine(&city, first.houses(), second.houses()); const TOP_LAYOUT_COUNT: usize = 10;
let chosen_layouts = sorted.iter().take(TOP_LAYOUT_COUNT).map(|l| l.houses()).collect();
eprintln!("Starting to combine {} top houses DB; vertical cuts", TOP_LAYOUT_COUNT);
combine::try_combine(&city, &chosen_layouts, &chosen_layouts);
} }

124
src/combine.rs

@ -2,36 +2,52 @@ use crate::city;
use crate::city::{City, House, SIZE, HOUSE_RANGE}; use crate::city::{City, House, SIZE, HOUSE_RANGE};
use itertools::Itertools; use itertools::Itertools;
use std::collections::VecDeque; use std::collections::VecDeque;
use std::collections::vec_deque::Iter;
pub fn try_combine(city: &City, layout1: &Vec<House>, layout2: &Vec<House>) { pub fn try_combine(city: &City, left_layouts: &Vec<&Vec<House>>, right_layouts: &Vec<&Vec<House>>) {
// Sorted in reverse so we can remove from the end // Sorted in reverse so we can remove from the end
let mut houses1_sorted: Vec<House> = layout1.iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect(); let mut left_houses_sorted: Vec<Vec<House>> = left_layouts.iter()
let mut houses2_sorted: Vec<House> = layout2.iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect(); .map(|l| l.iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect())
.collect();
let mut right_houses_sorted: Vec<Vec<House>> = right_layouts.iter()
.map(|l| l.iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect())
.collect();
// TODO: We may want to maintain K left sides and K right sides to compare K^2 layouts at once at each x let mut lefts = Vec::new();
let mut rights = Vec::new();
// houses1 is left, houses2 is right for _ in left_layouts {
lefts.push(LeftLine::new());
}
let mut left = LeftLine::new(); for mut right_layout in right_houses_sorted {
let mut right = RightLine::new(); let mut right = RightLine::new();
// Make sure that we include all houses initially // Make sure that we include all houses initially
while let Some(house) = houses2_sorted.pop() { while let Some(house) = right_layout.pop() {
right.add_house(house); right.add_house(house, &city);
}
rights.push(right);
} }
let mut best_price = None;
// x is the last left coordinate, x+1 is right // x is the last left coordinate, x+1 is right
for x in 0..SIZE { for x in 0..SIZE {
eprintln!("Starting x {}", x);
// Update the lines // Update the lines
while let Some(house) = houses1_sorted.last() { for (mut left_line, mut left_houses) in lefts.iter_mut().zip(left_houses_sorted.iter_mut()) {
while let Some(house) = left_houses.last() {
if house.x == x { if house.x == x {
left.add_house(*house); left_line.add_house(*house, &city);
houses1_sorted.pop(); left_houses.pop();
} else { } else {
break; break;
} }
} }
right.remove_houses(x); }
for mut right_line in rights.iter_mut() {
right_line.remove_houses(x, &city);
}
// Check compatibility of lines // Check compatibility of lines
if x == 0 { if x == 0 {
@ -40,22 +56,35 @@ pub fn try_combine(city: &City, layout1: &Vec<House>, layout2: &Vec<House>) {
continue; continue;
} }
let mut compatibles = 0;
let mut incompatibles = 0;
for (left_i, left) in lefts.iter().enumerate() {
for (right_i, right) in rights.iter().enumerate() {
if left_i == right_i {
// Do not compare the same layout
continue;
}
if is_compatible(city, &left, &right) { if is_compatible(city, &left, &right) {
eprintln!("Compatible on X {}", x); let price = left.price + right.price;
let houses: Vec<_> = layout1.iter().filter(|h| h.x <= x).chain(layout2.iter().filter(|h| h.x > x)).map(|h| *h).collect(); if best_price.is_none() || price < best_price.unwrap() {
eprintln!("Price {}", city::get_price(&city, &houses)); best_price = Some(price);
//if let Some(price) = city::is_valid(&city, &houses) { eprintln!("{} - new best score, cut on x {}, left {} - right {}, printing", price, x, left_i, right_i);
// eprintln!("Merge valid with price {}", price) println!("{} - new best score, cut on x {}, left {} - right {}", price, x, left_i, right_i);
//} else { let new_houses: Vec<_> = left.houses().chain(right.houses()).collect();
// eprintln!("Merge actually invalid, printing invalid merge"); println!("{}", new_houses.len());
// println!("{}", houses.len()); for house in new_houses {
// for house in houses { println!("{} {}", house.y, house.x);
// println!("{} {}", house.y, house.x); }
// } }
//} compatibles += 1;
} else { } else {
eprintln!("Incompatible on X {}", x); incompatibles += 1;
}
}
} }
eprintln!("{}/{} compatible", compatibles, compatibles + incompatibles);
} }
} }
@ -67,8 +96,6 @@ fn is_compatible(city: &City, left: &LeftLine, right: &RightLine) -> bool {
// This range will often be empty // This range will often be empty
for x in (max_left_covered_x+1)..min_right_covered_x { for x in (max_left_covered_x+1)..min_right_covered_x {
if city.is_house_xy(x, y) { 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; return false;
} }
} }
@ -78,53 +105,67 @@ fn is_compatible(city: &City, left: &LeftLine, right: &RightLine) -> bool {
} }
struct LeftLine { struct LeftLine {
covers: Vec<usize> covers: Vec<usize>,
houses: Vec<House>,
price: u32
} }
struct RightLine { struct RightLine {
covers: Vec<usize>, covers: Vec<usize>,
houses: VecDeque<House> houses: VecDeque<House>,
price: u32
} }
impl LeftLine { impl LeftLine {
pub fn new() -> Self { pub fn new() -> Self {
// XXX: Careful, default of 0 includes covering first vertical line // XXX: Careful, default of 0 includes covering first vertical line
let covers = vec![0; SIZE]; let covers = vec![0; SIZE];
LeftLine {covers} let houses = Vec::new();
LeftLine {covers, houses, price: 0 }
} }
pub fn add_house(&mut self, house: House) { pub fn add_house(&mut self, house: House, city: &City) {
let range_rect = house.range_rectangle(); let range_rect = house.range_rectangle();
for y in range_rect.top..=range_rect.bottom { for y in range_rect.top..=range_rect.bottom {
// Should always be the max variant // Should always be the max variant
self.covers[y] = self.covers[y].max(range_rect.right); self.covers[y] = self.covers[y].max(range_rect.right);
} }
self.price += city.get_price(house) as u32;
self.houses.push(house);
} }
pub fn get_max_covered_x(&self, y: usize) -> usize { pub fn get_max_covered_x(&self, y: usize) -> usize {
self.covers[y] self.covers[y]
} }
pub fn get_side_price(&self) -> u32 {
self.price
}
pub fn houses(&self) -> std::slice::Iter<'_, House> {
self.houses.iter()
}
} }
impl RightLine { impl RightLine {
pub fn new() -> Self { pub fn new() -> Self {
let covers = vec![usize::MAX; SIZE]; let covers = vec![usize::MAX; SIZE];
let houses = VecDeque::new(); let houses = VecDeque::new();
RightLine {covers, houses} RightLine {covers, houses, price: 0}
} }
pub fn add_house(&mut self, house: House) { pub fn add_house(&mut self, house: House, city: &City) {
// Added houses have to always be ordered by x // 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(); let range_rect = house.range_rectangle();
for y in range_rect.top..=range_rect.bottom { for y in range_rect.top..=range_rect.bottom {
self.covers[y] = self.covers[y].min(range_rect.left); self.covers[y] = self.covers[y].min(range_rect.left);
} }
self.houses.push_back(house); self.houses.push_back(house);
self.price += city.get_price(house) as u32
} }
pub fn remove_houses(&mut self, x: usize) { pub fn remove_houses(&mut self, x: usize, city: &City) {
// Has to be called with x, x+1, x+2... // Has to be called with x, x+1, x+2...
while let Some(house) = self.houses.front() { while let Some(house) = self.houses.front() {
if house.x == x { if house.x == x {
@ -140,7 +181,6 @@ impl RightLine {
// intersects the removed area // intersects the removed area
for house in &self.houses { for house in &self.houses {
let house_rect = house.range_rectangle(); let house_rect = house.range_rectangle();
// TODO: Verify this intersection is correct
let y_intersection = if removed_house.y < house.y { let y_intersection = if removed_house.y < house.y {
house_rect.top..=removed_rect.bottom house_rect.top..=removed_rect.bottom
} else { } else {
@ -151,6 +191,8 @@ impl RightLine {
self.covers[y] = self.covers[y].min(house_rect.left); self.covers[y] = self.covers[y].min(house_rect.left);
} }
} }
self.price -= city.get_price(removed_house) as u32;
} else { } else {
break; break;
} }
@ -160,4 +202,12 @@ impl RightLine {
pub fn get_min_covered_x(&self, y: usize) -> usize { pub fn get_min_covered_x(&self, y: usize) -> usize {
self.covers[y].min(SIZE) self.covers[y].min(SIZE)
} }
pub fn get_side_price(&self) -> u32 {
self.price
}
pub fn houses(&self) -> Iter<'_, House> {
self.houses.iter()
}
} }

Loading…
Cancel
Save