|
|
@ -1,11 +1,12 @@ |
|
|
|
use crate::city; |
|
|
|
use crate::city::{City, House, SIZE, HOUSE_RANGE}; |
|
|
|
use crate::db::LayoutDB; |
|
|
|
use crate::city::{City, House, SIZE}; |
|
|
|
use itertools::Itertools; |
|
|
|
use itertools::iproduct; |
|
|
|
use std::collections::VecDeque; |
|
|
|
use std::collections::vec_deque::Iter; |
|
|
|
|
|
|
|
pub fn try_combine(city: &City, left_layouts: &Vec<Vec<House>>, right_layouts: &Vec<Vec<House>>, print_transposed: bool) { |
|
|
|
pub fn try_combine(city: &City, left_layouts: &Vec<Vec<House>>, right_layouts: &Vec<Vec<House>>, db: &mut LayoutDB, transposed: bool) { |
|
|
|
// Sorted in reverse so we can remove from the end
|
|
|
|
let mut left_houses_sorted: Vec<Vec<House>> = left_layouts.iter() |
|
|
|
.map(|l| l.iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect()) |
|
|
@ -30,10 +31,13 @@ pub fn try_combine(city: &City, left_layouts: &Vec<Vec<House>>, right_layouts: & |
|
|
|
rights.push(right); |
|
|
|
} |
|
|
|
|
|
|
|
let mut best_price = None; |
|
|
|
let mut best_price = left_layouts.iter().chain(right_layouts.iter()) |
|
|
|
.map(|layout| city::get_price(&city, layout)) |
|
|
|
.min(); |
|
|
|
|
|
|
|
// x is the last left coordinate, x+1 is right
|
|
|
|
for x in 0..SIZE { |
|
|
|
if print_transposed { |
|
|
|
if transposed { |
|
|
|
eprintln!("Starting y {}", x); |
|
|
|
} else { |
|
|
|
eprintln!("Starting x {}", x); |
|
|
@ -63,7 +67,7 @@ pub fn try_combine(city: &City, left_layouts: &Vec<Vec<House>>, right_layouts: & |
|
|
|
} |
|
|
|
|
|
|
|
let pairs: Vec<_> = iproduct!(lefts.iter().enumerate(), rights.iter().enumerate()) |
|
|
|
.filter(|((left_i, left), (right_i, right))| left_i != right_i) |
|
|
|
.filter(|((left_i, _), (right_i, _))| left_i != right_i) |
|
|
|
.map(|((left_i, left), (right_i, right))| (left, right, left.price + right.price, left_i, right_i)) |
|
|
|
.sorted_by(|(_, _, price1, _, _), (_, _, price2, _, _)| price1.cmp(&price2)) |
|
|
|
.collect(); |
|
|
@ -74,23 +78,20 @@ pub fn try_combine(city: &City, left_layouts: &Vec<Vec<House>>, right_layouts: & |
|
|
|
if is_compatible(city, &left, &right) { |
|
|
|
if best_price.is_none() || price < best_price.unwrap() { |
|
|
|
best_price = Some(price); |
|
|
|
if print_transposed { |
|
|
|
eprintln!("{} - new best score, cut on y {}, left {} - right {}, printing", price, x, left_i, right_i); |
|
|
|
println!("{} - new best score, cut on y {}, left {} - right {}", price, x, left_i, right_i); |
|
|
|
let new_houses: Vec<_> = left.houses().chain(right.houses()).collect(); |
|
|
|
println!("{}", new_houses.len()); |
|
|
|
for house in new_houses { |
|
|
|
println!("{} {}", house.x, house.y); |
|
|
|
} |
|
|
|
} else { |
|
|
|
eprintln!("{} - new best score, cut on x {}, left {} - right {}, printing", price, x, left_i, right_i); |
|
|
|
println!("{} - new best score, cut on x {}, left {} - right {}", price, x, left_i, right_i); |
|
|
|
let new_houses: Vec<_> = left.houses().chain(right.houses()).collect(); |
|
|
|
println!("{}", new_houses.len()); |
|
|
|
for house in new_houses { |
|
|
|
println!("{} {}", house.y, house.x); |
|
|
|
} |
|
|
|
let axis = if transposed { "y" } else { "x" }; |
|
|
|
eprintln!("{} - new best score, cut on {} {}, left {} - right {}, printing", axis, price, x, left_i, right_i); |
|
|
|
println!("{} - new best score, cut on {} {}, left {} - right {}", axis, price, x, left_i, right_i); |
|
|
|
let mut new_houses: Vec<_> = left.houses().copied().chain(right.houses().copied()).collect(); |
|
|
|
if transposed { |
|
|
|
new_houses = transpose_layout(&new_houses); |
|
|
|
} |
|
|
|
println!("{}", new_houses.len()); |
|
|
|
for house in &new_houses { |
|
|
|
println!("{} {}", house.y, house.x); |
|
|
|
} |
|
|
|
|
|
|
|
// We only add best results to avoid overfilling the database with similar layouts
|
|
|
|
db.add_layout(&new_houses, true); |
|
|
|
} |
|
|
|
compatibles += 1; |
|
|
|
|
|
|
@ -111,7 +112,7 @@ fn is_compatible(city: &City, left: &LeftLine, right: &RightLine) -> bool { |
|
|
|
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 { |
|
|
|
for x in (max_left_covered_x + 1)..min_right_covered_x { |
|
|
|
if city.is_house_xy(x, y) { |
|
|
|
return false; |
|
|
|
} |
|
|
@ -124,13 +125,13 @@ fn is_compatible(city: &City, left: &LeftLine, right: &RightLine) -> bool { |
|
|
|
struct LeftLine { |
|
|
|
covers: Vec<usize>, |
|
|
|
houses: Vec<House>, |
|
|
|
price: u32 |
|
|
|
price: u32, |
|
|
|
} |
|
|
|
|
|
|
|
struct RightLine { |
|
|
|
covers: Vec<usize>, |
|
|
|
houses: VecDeque<House>, |
|
|
|
price: u32 |
|
|
|
price: u32, |
|
|
|
} |
|
|
|
|
|
|
|
impl LeftLine { |
|
|
@ -138,7 +139,7 @@ impl LeftLine { |
|
|
|
// XXX: Careful, default of 0 includes covering first vertical line
|
|
|
|
let covers = vec![0; SIZE]; |
|
|
|
let houses = Vec::new(); |
|
|
|
LeftLine {covers, houses, price: 0 } |
|
|
|
LeftLine { covers, houses, price: 0 } |
|
|
|
} |
|
|
|
|
|
|
|
pub fn add_house(&mut self, house: House, city: &City) { |
|
|
@ -168,7 +169,7 @@ impl RightLine { |
|
|
|
pub fn new() -> Self { |
|
|
|
let covers = vec![usize::MAX; SIZE]; |
|
|
|
let houses = VecDeque::new(); |
|
|
|
RightLine {covers, houses, price: 0} |
|
|
|
RightLine { covers, houses, price: 0 } |
|
|
|
} |
|
|
|
|
|
|
|
pub fn add_house(&mut self, house: House, city: &City) { |
|
|
@ -228,3 +229,12 @@ impl RightLine { |
|
|
|
self.houses.iter() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
pub fn transpose_layout(houses: &Vec<House>) -> Vec<House> { |
|
|
|
let mut transposed = Vec::new(); |
|
|
|
for house in houses { |
|
|
|
transposed.push(House::new(house.y, house.x)); |
|
|
|
} |
|
|
|
|
|
|
|
transposed |
|
|
|
} |
|
|
|