Browse Source

Allow Cities of any sizes

This will be useful for optimizing parts of the map independently.
master
Jirka Sejkora 3 years ago
parent
commit
f694e4701a
  1. 129
      src/city.rs
  2. 14
      src/combine-layouts.rs
  3. 50
      src/combine.rs
  4. 2
      src/main.rs
  5. 30
      src/optimization.rs
  6. 10
      src/population.rs

129
src/city.rs

@ -1,45 +1,49 @@
use std::fmt; use std::fmt;
use std::fmt::Formatter; use std::fmt::Formatter;
pub const SIZE: usize = 16384; pub const INPUT_CITY_WIDTH: usize = 16384;
pub const INPUT_CITY_HEIGHT: usize = 16384;
pub const HOUSE_RANGE: usize = 500; pub const HOUSE_RANGE: usize = 500;
pub struct City { pub struct City {
prices: Vec<u16>, prices: Vec<u16>,
buyable_house_count: usize buyable_house_count: usize,
width: usize,
height: usize
} }
impl City { impl City {
pub fn read_from_file(filename: &str) -> Self { pub fn read_from_file(filename: &str, width: usize, height: usize) -> Self {
let values = std::fs::read(filename).unwrap(); let values = std::fs::read(filename).unwrap();
let mut prices: Vec<u16> = Vec::new(); let mut prices: Vec<u16> = Vec::new();
for y in 0..SIZE { for y in 0..height {
for x in 0..SIZE { for x in 0..width {
let price = (values[(y * SIZE + x) * 2] as u16) | ((values[(y * SIZE + x) * 2 + 1] as u16) << 8); let price = (values[(y * width + x) * 2] as u16) | ((values[(y * width + x) * 2 + 1] as u16) << 8);
prices.push(price); prices.push(price);
} }
} }
City::new(prices) City::new(prices, width, height)
} }
pub fn new(prices: Vec<u16>) -> Self { pub fn new(prices: Vec<u16>, width: usize, height: usize) -> Self {
let mut buyable_house_count = 0; let mut buyable_house_count = 0;
for &price in &prices { for &price in &prices {
if price > 0 { if price > 0 {
buyable_house_count += 1; buyable_house_count += 1;
} }
} }
City { prices, buyable_house_count } City { prices, buyable_house_count, width, height }
} }
pub fn get_price(&self, house: House) -> u16 { pub fn get_price(&self, house: House) -> u16 {
self.prices[house.y * SIZE + house.x] self.prices[house.y * self.width + house.x]
} }
pub fn get_price_xy(&self, x: usize, y: usize) -> u16 { pub fn get_price_xy(&self, x: usize, y: usize) -> u16 {
self.prices[y * SIZE + x] self.prices[y * self.width + x]
} }
pub fn is_house(&self, house: House) -> bool { pub fn is_house(&self, house: House) -> bool {
@ -53,6 +57,13 @@ impl City {
pub fn get_house_count(&self) -> usize { pub fn get_house_count(&self) -> usize {
self.buyable_house_count self.buyable_house_count
} }
pub fn width(&self) -> usize {
self.width
}
pub fn height(&self) -> usize {
self.height
}
} }
#[derive(Eq, PartialEq, Hash, Copy, Clone)] #[derive(Eq, PartialEq, Hash, Copy, Clone)]
@ -66,11 +77,11 @@ impl House {
House { x, y } House { x, y }
} }
pub fn range_rectangle(&self) -> Rectangle { pub fn range_rectangle(&self, city: &City) -> Rectangle {
let top = if self.y <= HOUSE_RANGE { 0 } else { self.y - HOUSE_RANGE }; let top = if self.y <= HOUSE_RANGE { 0 } else { self.y - HOUSE_RANGE };
let bottom = if self.y >= SIZE - 1 - HOUSE_RANGE { SIZE - 1 } else { self.y + HOUSE_RANGE }; let bottom = if self.y >= city.height() - 1 - HOUSE_RANGE { city.height() - 1 } else { self.y + HOUSE_RANGE };
let left = if self.x <= HOUSE_RANGE { 0 } else { self.x - HOUSE_RANGE }; let left = if self.x <= HOUSE_RANGE { 0 } else { self.x - HOUSE_RANGE };
let right = if self.x >= SIZE - 1 - HOUSE_RANGE { SIZE - 1 } else { self.x + HOUSE_RANGE }; let right = if self.x >= city.width() - 1 - HOUSE_RANGE { city.width() - 1 } else { self.x + HOUSE_RANGE };
Rectangle {top, bottom, left, right} Rectangle {top, bottom, left, right}
} }
} }
@ -117,15 +128,15 @@ pub struct HouseLayout<'a> {
impl<'a> HouseLayout<'a> { impl<'a> HouseLayout<'a> {
pub fn new(city: &'a City) -> Self { pub fn new(city: &'a City) -> Self {
HouseLayout { city, reachable: vec![0; SIZE * SIZE], houses: Vec::new(), reachable_houses: 0 } HouseLayout { city, reachable: vec![0; city.width() * city.height()], houses: Vec::new(), reachable_houses: 0 }
} }
pub fn cover_count(&self, house: House) -> u16 { pub fn cover_count(&self, house: House) -> u16 {
self.reachable[house.y * SIZE + house.x] self.reachable[house.y * self.city.width + house.x]
} }
pub fn cover_count_xy(&self, x: usize, y: usize) -> u16 { pub fn cover_count_xy(&self, x: usize, y: usize) -> u16 {
self.reachable[y * SIZE + x] self.reachable[y * self.city.width + x]
} }
pub fn is_covered(&self, house: House) -> bool { pub fn is_covered(&self, house: House) -> bool {
@ -133,10 +144,10 @@ impl<'a> HouseLayout<'a> {
} }
pub fn add_house(&mut self, house: House) -> usize { pub fn add_house(&mut self, house: House) -> usize {
let range_rect = house.range_rectangle(); let range_rect = house.range_rectangle(self.city);
for y in range_rect.top..=range_rect.bottom { for y in range_rect.top..=range_rect.bottom {
for x in range_rect.left..=range_rect.right { for x in range_rect.left..=range_rect.right {
let index = y as usize * SIZE + x as usize; let index = y as usize * self.city.width + x as usize;
if self.reachable[index] == 0 && self.city.is_house_xy(x as usize, y as usize) { if self.reachable[index] == 0 && self.city.is_house_xy(x as usize, y as usize) {
self.reachable_houses += 1; self.reachable_houses += 1;
@ -152,10 +163,10 @@ impl<'a> HouseLayout<'a> {
pub fn remove_house(&mut self, index: usize) { pub fn remove_house(&mut self, index: usize) {
let house = self.houses.swap_remove(index); let house = self.houses.swap_remove(index);
let range_rect = house.range_rectangle(); let range_rect = house.range_rectangle(self.city);
for y in range_rect.top..=range_rect.bottom { for y in range_rect.top..=range_rect.bottom {
for x in range_rect.left..=range_rect.right { for x in range_rect.left..=range_rect.right {
let index = y as usize * SIZE + x as usize; let index = y as usize * self.city.width + x as usize;
self.reachable[index] -= 1; self.reachable[index] -= 1;
@ -189,24 +200,24 @@ pub fn get_price(city: &City, houses: &Vec<House>) -> u32 {
} }
pub fn is_valid(city: &City, houses: &Vec<House>) -> Option<u32> { pub fn is_valid(city: &City, houses: &Vec<House>) -> Option<u32> {
let mut reachable = vec![false; SIZE * SIZE]; let mut reachable = vec![false; city.width() * city.height()];
let mut price = 0u32; let mut price = 0u32;
for house in houses { for house in houses {
assert!(city.prices[house.y * SIZE + house.x] > 0); assert!(city.is_house(*house));
let range_rect = house.range_rectangle(); let range_rect = house.range_rectangle(city);
for y in range_rect.top..=range_rect.bottom { for y in range_rect.top..=range_rect.bottom {
for x in range_rect.left..=range_rect.right { for x in range_rect.left..=range_rect.right {
reachable[y as usize * SIZE + x as usize] = true; reachable[y as usize * city.width() + x as usize] = true;
} }
} }
price += city.get_price(*house) as u32; price += city.get_price(*house) as u32;
} }
for y in 0..SIZE { for y in 0..city.height {
for x in 0..SIZE { for x in 0..city.width {
if !reachable[y * SIZE + x] && city.prices[y * SIZE + x] > 0 { if !reachable[y * city.width + x] && city.prices[y * city.width + x] > 0 {
return None; return None;
} }
} }
@ -217,35 +228,35 @@ pub fn is_valid(city: &City, houses: &Vec<House>) -> Option<u32> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use super::*; //use super::*;
#[test] //#[test]
fn house_rectangle_at_min() { //fn house_rectangle_at_min() {
let house = House::new(0, 0); // let house = House::new(0, 0);
let rect = house.range_rectangle(); // let rect = house.range_rectangle();
assert_eq!(rect.top, 0); // assert_eq!(rect.top, 0);
assert_eq!(rect.left, 0); // assert_eq!(rect.left, 0);
assert_eq!(rect.right, HOUSE_RANGE); // assert_eq!(rect.right, HOUSE_RANGE);
assert_eq!(rect.bottom, HOUSE_RANGE); // assert_eq!(rect.bottom, HOUSE_RANGE);
} //}
#[test] //#[test]
fn house_rectangle_at_max() { //fn house_rectangle_at_max() {
let house = House::new(SIZE - 1, SIZE - 1); // let house = House::new(SIZE - 1, SIZE - 1);
let rect = house.range_rectangle(); // let rect = house.range_rectangle();
assert_eq!(rect.top, SIZE - 1 - HOUSE_RANGE); // assert_eq!(rect.top, SIZE - 1 - HOUSE_RANGE);
assert_eq!(rect.left, SIZE - 1 - HOUSE_RANGE); // assert_eq!(rect.left, SIZE - 1 - HOUSE_RANGE);
assert_eq!(rect.right, SIZE - 1); // assert_eq!(rect.right, SIZE - 1);
assert_eq!(rect.bottom, SIZE - 1); // assert_eq!(rect.bottom, SIZE - 1);
} //}
#[test] //#[test]
fn house_rect_in_middle() { //fn house_rect_in_middle() {
let house = House::new(SIZE / 2, SIZE / 2); // let house = House::new(SIZE / 2, SIZE / 2);
let rect = house.range_rectangle(); // let rect = house.range_rectangle();
assert_eq!(rect.top, house.y - HOUSE_RANGE); // assert_eq!(rect.top, house.y - HOUSE_RANGE);
assert_eq!(rect.left, house.x - HOUSE_RANGE); // assert_eq!(rect.left, house.x - HOUSE_RANGE);
assert_eq!(rect.right, house.x + HOUSE_RANGE); // assert_eq!(rect.right, house.x + HOUSE_RANGE);
assert_eq!(rect.bottom, house.y + HOUSE_RANGE); // assert_eq!(rect.bottom, house.y + HOUSE_RANGE);
} //}
} }

14
src/combine-layouts.rs

@ -1,5 +1,5 @@
use db::{LayoutDB, SavedLayout}; use db::{LayoutDB, SavedLayout};
use city::{City, House, SIZE}; use city::{City, House};
use itertools::Itertools; use itertools::Itertools;
use crate::combine::transpose_layout; use crate::combine::transpose_layout;
@ -16,7 +16,7 @@ fn main() {
let mut db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB"); let mut db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB");
eprintln!("Loaded the DB, {} stored layouts", db.layouts().len()); eprintln!("Loaded the DB, {} stored layouts", db.layouts().len());
let city = City::read_from_file("01.in"); let city = City::read_from_file("01.in", city::INPUT_CITY_WIDTH, city::INPUT_CITY_HEIGHT);
eprintln!("Loaded the city file, {} houses", city.get_house_count()); eprintln!("Loaded the city file, {} houses", city.get_house_count());
eprintln!("Building a transposed city..."); eprintln!("Building a transposed city...");
@ -61,16 +61,16 @@ fn main() {
} }
fn transpose_city(city: &City) -> City { fn transpose_city(city: &City) -> City {
let mut transposed_prices = vec![0u16; SIZE * SIZE]; let mut transposed_prices = vec![0u16; city.width() * city.height()];
for y in 0..SIZE { for y in 0..city.height() {
for x in 0..SIZE { for x in 0..city.width() {
// Sorry, cache! Not worth optimizing with blocks, // Sorry, cache! Not worth optimizing with blocks,
// this is not going to be ran often. // this is not going to be ran often.
transposed_prices[y * SIZE + x] = city.get_price_xy(y, x); transposed_prices[x * city.height() + y] = city.get_price_xy(x, y);
} }
} }
City::new(transposed_prices) City::new(transposed_prices, city.height(), city.width())
} }
fn transpose_saved_layout(layout: &SavedLayout) -> SavedLayout { fn transpose_saved_layout(layout: &SavedLayout) -> SavedLayout {

50
src/combine.rs

@ -1,6 +1,6 @@
use crate::city; use crate::city;
use crate::db::{LayoutDB, SavedLayout, MergeLowerBound}; use crate::db::{LayoutDB, SavedLayout, MergeLowerBound};
use crate::city::{City, House, SIZE}; use crate::city::{City, House};
use itertools::Itertools; use itertools::Itertools;
use itertools::iproduct; use itertools::iproduct;
use std::collections::{VecDeque, HashMap}; use std::collections::{VecDeque, HashMap};
@ -9,12 +9,12 @@ use std::collections::vec_deque::Iter;
struct LeftState<'a> { struct LeftState<'a> {
layout: &'a SavedLayout, layout: &'a SavedLayout,
sorted_houses: Vec<House>, sorted_houses: Vec<House>,
line: LeftLine line: LeftLine<'a>
} }
struct RightState<'a> { struct RightState<'a> {
layout: &'a SavedLayout, layout: &'a SavedLayout,
line: RightLine line: RightLine<'a>
} }
pub struct CompatibilityCache { pub struct CompatibilityCache {
@ -73,7 +73,7 @@ pub fn create_new_best_combination(city: &City, left_layouts: &Vec<SavedLayout>,
lefts.push(LeftState { lefts.push(LeftState {
layout: &left_layout, layout: &left_layout,
sorted_houses, sorted_houses,
line: LeftLine::new() line: LeftLine::new(&city)
}); });
} }
@ -97,7 +97,7 @@ pub fn create_new_best_combination(city: &City, left_layouts: &Vec<SavedLayout>,
let mut sorted_houses: Vec<_> = right_layout.houses().iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect(); let mut sorted_houses: Vec<_> = right_layout.houses().iter().sorted_by(|h1, h2| h2.x.cmp(&h1.x)).map(|x| *x).collect();
let mut line = RightLine::new(); let mut line = RightLine::new(&city);
// Make sure that we include all houses initially // Make sure that we include all houses initially
while let Some(house) = sorted_houses.pop() { while let Some(house) = sorted_houses.pop() {
line.add_house(house, &city); line.add_house(house, &city);
@ -111,7 +111,7 @@ pub fn create_new_best_combination(city: &City, left_layouts: &Vec<SavedLayout>,
let axis = if transposed { "y" } else { "x" }; let axis = if transposed { "y" } else { "x" };
// 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..city.width() {
eprintln!("Starting {} {}", axis, x); eprintln!("Starting {} {}", axis, x);
// Update the lines // Update the lines
@ -215,7 +215,7 @@ pub fn create_new_best_combination(city: &City, left_layouts: &Vec<SavedLayout>,
} }
fn is_compatible(city: &City, left: &LeftLine, right: &RightLine) -> bool { fn is_compatible(city: &City, left: &LeftLine, right: &RightLine) -> bool {
for y in 0..SIZE { for y in 0..city.height() {
let max_left_covered_x = left.get_max_covered_x(y); let max_left_covered_x = left.get_max_covered_x(y);
let min_right_covered_x = right.get_min_covered_x(y); let min_right_covered_x = right.get_min_covered_x(y);
@ -230,30 +230,32 @@ fn is_compatible(city: &City, left: &LeftLine, right: &RightLine) -> bool {
true true
} }
struct LeftLine { struct LeftLine<'a> {
covers: Vec<usize>, covers: Vec<usize>,
houses: Vec<House>, houses: Vec<House>,
price: u32, price: u32,
last_update_x: usize last_update_x: usize,
city: &'a City
} }
struct RightLine { struct RightLine<'a> {
covers: Vec<usize>, covers: Vec<usize>,
houses: VecDeque<House>, houses: VecDeque<House>,
price: u32, price: u32,
last_update_x: usize last_update_x: usize,
city: &'a City
} }
impl LeftLine { impl<'a> LeftLine<'a> {
pub fn new() -> Self { pub fn new(city: &'a City) -> 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; city.height()];
let houses = Vec::new(); let houses = Vec::new();
LeftLine { covers, houses, price: 0, last_update_x: 0 } LeftLine { covers, houses, price: 0, last_update_x: 0, city }
} }
pub fn add_house(&mut self, house: House, city: &City) { pub fn add_house(&mut self, house: House, city: &City) {
let range_rect = house.range_rectangle(); let range_rect = house.range_rectangle(city);
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);
@ -276,16 +278,16 @@ impl LeftLine {
} }
} }
impl RightLine { impl<'a> RightLine<'a> {
pub fn new() -> Self { pub fn new(city: &'a City) -> Self {
let covers = vec![usize::MAX; SIZE]; let covers = vec![usize::MAX; city.height()];
let houses = VecDeque::new(); let houses = VecDeque::new();
RightLine { covers, houses, price: 0, last_update_x: 0 } RightLine { covers, houses, price: 0, last_update_x: 0, city }
} }
pub fn add_house(&mut self, house: House, city: &City) { 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
let range_rect = house.range_rectangle(); let range_rect = house.range_rectangle(city);
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);
} }
@ -300,7 +302,7 @@ impl RightLine {
while let Some(house) = self.houses.front() { while let Some(house) = self.houses.front() {
if house.x == x { if house.x == x {
let removed_house = self.houses.pop_front().unwrap(); let removed_house = self.houses.pop_front().unwrap();
let removed_rect = removed_house.range_rectangle(); let removed_rect = removed_house.range_rectangle(city);
// Remove the now-outdated distances around the removed house // Remove the now-outdated distances around the removed house
for y in removed_rect.top..=removed_rect.bottom { for y in removed_rect.top..=removed_rect.bottom {
@ -310,7 +312,7 @@ impl RightLine {
// Update distances around the removed house if the area of any houses // Update distances around the removed house if the area of any houses
// 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(city);
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 {
@ -331,7 +333,7 @@ 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(self.city.width())
} }
pub fn get_side_price(&self) -> u32 { pub fn get_side_price(&self) -> u32 {

2
src/main.rs

@ -26,7 +26,7 @@ fn main() {
let mut db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB"); let mut db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB");
eprintln!("Loaded the DB, {} stored layouts", db.layouts().len()); eprintln!("Loaded the DB, {} stored layouts", db.layouts().len());
let city = City::read_from_file("01.in"); let city = City::read_from_file("01.in", city::INPUT_CITY_WIDTH, city::INPUT_CITY_HEIGHT);
eprintln!("Loaded the city file, {} houses", city.get_house_count()); eprintln!("Loaded the city file, {} houses", city.get_house_count());
const MIN_WEIGHT_SCORE: f64 = 540000.; const MIN_WEIGHT_SCORE: f64 = 540000.;

30
src/optimization.rs

@ -1,6 +1,6 @@
use std::collections::HashSet; use std::collections::HashSet;
use rand::prelude::{SliceRandom, StdRng}; use rand::prelude::{SliceRandom, StdRng};
use crate::city::{Rectangle, HOUSE_RANGE, SIZE, House, HouseLayout}; use crate::city::{Rectangle, HOUSE_RANGE, House, HouseLayout};
use itertools::iproduct; use itertools::iproduct;
pub enum RectangleSearchError { pub enum RectangleSearchError {
@ -15,13 +15,13 @@ fn get_valid_move_rectangle_multiple(layout: &HouseLayout, houses: &Vec<House>)
// We first establish a bounding box for an that has to be covered if all houses are removed. // We first establish a bounding box for an that has to be covered if all houses are removed.
let mut covered_rect: Option<Rectangle> = None; let mut covered_rect: Option<Rectangle> = None;
for house in houses { for house in houses {
let range_rect = house.range_rectangle(); let range_rect = house.range_rectangle(layout.city);
for y in range_rect.top..=range_rect.bottom { for y in range_rect.top..=range_rect.bottom {
for x in range_rect.left..=range_rect.right { for x in range_rect.left..=range_rect.right {
// We count how many rectangles of houses contain this xy position. // We count how many rectangles of houses contain this xy position.
let mut rectangles_containing_count = 0; let mut rectangles_containing_count = 0;
for house in houses { for house in houses {
let rect = house.range_rectangle(); let rect = house.range_rectangle(layout.city);
if rect.is_inside(x, y) { if rect.is_inside(x, y) {
rectangles_containing_count += 1; rectangles_containing_count += 1;
} }
@ -57,8 +57,8 @@ fn get_valid_move_rectangle_multiple(layout: &HouseLayout, houses: &Vec<House>)
let top = (covered_rect.top as i32 - height_margin).max(0) as usize; let top = (covered_rect.top as i32 - height_margin).max(0) as usize;
let left = (covered_rect.left as i32 - width_margin).max(0) as usize; let left = (covered_rect.left as i32 - width_margin).max(0) as usize;
let bottom = (covered_rect.bottom + height_margin as usize).min(SIZE - 1); let bottom = (covered_rect.bottom + height_margin as usize).min(layout.city.height() - 1);
let right = (covered_rect.right + width_margin as usize).min(SIZE - 1); let right = (covered_rect.right + width_margin as usize).min(layout.city.width() - 1);
if top > bottom || left > right { if top > bottom || left > right {
// Unsatisfiable rectangle by one house // Unsatisfiable rectangle by one house
@ -72,7 +72,7 @@ fn get_valid_move_rectangle(layout: &HouseLayout, house: House) -> Result<Rectan
// We first establish a bounding box for an that has to be covered if the house is removed. // We first establish a bounding box for an that has to be covered if the house is removed.
let mut covered_rect: Option<Rectangle> = None; let mut covered_rect: Option<Rectangle> = None;
let range_rect = house.range_rectangle(); let range_rect = house.range_rectangle(layout.city);
for y in range_rect.top..=range_rect.bottom { for y in range_rect.top..=range_rect.bottom {
for x in range_rect.left..=range_rect.right { for x in range_rect.left..=range_rect.right {
if layout.cover_count_xy(x, y) == 1 && layout.city.is_house_xy(x, y) { if layout.cover_count_xy(x, y) == 1 && layout.city.is_house_xy(x, y) {
@ -102,9 +102,9 @@ fn get_valid_move_rectangle(layout: &HouseLayout, house: House) -> Result<Rectan
let dist_bottom = range_rect.bottom - covered_rect.bottom; let dist_bottom = range_rect.bottom - covered_rect.bottom;
let left = if house.x <= dist_right { 0 } else { house.x - dist_right }; let left = if house.x <= dist_right { 0 } else { house.x - dist_right };
let right = if house.x >= SIZE - 1 - dist_left { SIZE - 1 } else { house.x + dist_left }; let right = if house.x >= layout.city.width() - 1 - dist_left { layout.city.width() - 1 } else { house.x + dist_left };
let top = if house.y <= dist_bottom { 0 } else { house.y - dist_bottom }; let top = if house.y <= dist_bottom { 0 } else { house.y - dist_bottom };
let bottom = if house.y >= SIZE - 1 - dist_top { SIZE - 1 } else { house.y + dist_top }; let bottom = if house.y >= layout.city.height() - 1 - dist_top { layout.city.height() - 1 } else { house.y + dist_top };
let valid_move_rectangle = Rectangle { let valid_move_rectangle = Rectangle {
left, right, top, bottom left, right, top, bottom
@ -341,8 +341,8 @@ fn get_dual_move_distances(layout: &HouseLayout, house1_index: usize, house2_ind
let house1 = layout.houses()[house1_index]; let house1 = layout.houses()[house1_index];
let house2 = layout.houses()[house2_index]; let house2 = layout.houses()[house2_index];
let rect1 = house1.range_rectangle(); let rect1 = house1.range_rectangle(layout.city);
let rect2 = house2.range_rectangle(); let rect2 = house2.range_rectangle(layout.city);
let top1 = rect1.top.min(rect2.top); let top1 = rect1.top.min(rect2.top);
let top2 = rect1.top.max(rect2.top); let top2 = rect1.top.max(rect2.top);
@ -365,10 +365,10 @@ fn get_dual_move_distances(layout: &HouseLayout, house1_index: usize, house2_ind
let shared_y = top2..=bottom1; let shared_y = top2..=bottom1;
let margin_bottom = bottom1 + 1..=bottom2; let margin_bottom = bottom1 + 1..=bottom2;
let mut top_distance = SIZE; let mut top_distance = usize::MAX;
let mut bottom_distance = SIZE; let mut bottom_distance = usize::MAX;
let mut right_distance = SIZE; let mut right_distance = usize::MAX;
let mut left_distance = SIZE; let mut left_distance = usize::MAX;
// We check the same tile twice if it's in both rectangles (and both shared_x and shared_y), // We check the same tile twice if it's in both rectangles (and both shared_x and shared_y),
// this could be made more efficient by dividing the rectangles into 5 zones. // this could be made more efficient by dividing the rectangles into 5 zones.
@ -409,7 +409,7 @@ fn get_dual_move_distances(layout: &HouseLayout, house1_index: usize, house2_ind
} }
// TODO: Handle properly // TODO: Handle properly
assert_ne!(top_distance, SIZE); assert_ne!(top_distance, usize::MAX);
Some(MoveDistances { Some(MoveDistances {
left: left_distance, left: left_distance,

10
src/population.rs

@ -1,5 +1,5 @@
use rand::Rng; use rand::Rng;
use crate::city::{SIZE, House, HouseLayout, City}; use crate::city::{House, HouseLayout, City};
use rand::prelude::*; use rand::prelude::*;
use crate::db::{LayoutDB, SavedLayout}; use crate::db::{LayoutDB, SavedLayout};
use crate::city; use crate::city;
@ -11,8 +11,8 @@ use rand::distributions::WeightedIndex;
pub fn populate_random(layout: &mut HouseLayout, rng: &mut StdRng) { pub fn populate_random(layout: &mut HouseLayout, rng: &mut StdRng) {
loop { loop {
loop { loop {
let x = rng.gen_range(0..SIZE); let x = rng.gen_range(0..layout.city.width());
let y = rng.gen_range(0..SIZE); let y = rng.gen_range(0..layout.city.height());
let house = House::new(x, y); let house = House::new(x, y);
if layout.city.is_house_xy(x, y) && !layout.is_covered(house) { if layout.city.is_house_xy(x, y) && !layout.is_covered(house) {
layout.add_house(house); layout.add_house(house);
@ -59,8 +59,8 @@ pub fn populate_using_db(layout: &mut HouseLayout, mut rng: &mut StdRng, db: &La
} }
} else { } else {
loop { loop {
let x = rng.gen_range(0..SIZE); let x = rng.gen_range(0..layout.city.width());
let y = rng.gen_range(0..SIZE); let y = rng.gen_range(0..layout.city.height());
let house = House::new(x, y); let house = House::new(x, y);
if layout.city.is_house_xy(x, y) && !layout.is_covered(house) { if layout.city.is_house_xy(x, y) && !layout.is_covered(house) {
layout.add_house(house); layout.add_house(house);

Loading…
Cancel
Save