Allow Cities of any sizes
This will be useful for optimizing parts of the map independently.
This commit is contained in:
parent
109b5fac01
commit
f694e4701a
6 changed files with 121 additions and 108 deletions
123
src/city.rs
123
src/city.rs
|
@ -1,45 +1,49 @@
|
|||
use std::fmt;
|
||||
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 struct City {
|
||||
prices: Vec<u16>,
|
||||
buyable_house_count: usize
|
||||
buyable_house_count: usize,
|
||||
width: usize,
|
||||
height: usize
|
||||
}
|
||||
|
||||
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 mut prices: Vec<u16> = Vec::new();
|
||||
|
||||
for y in 0..SIZE {
|
||||
for x in 0..SIZE {
|
||||
let price = (values[(y * SIZE + x) * 2] as u16) | ((values[(y * SIZE + x) * 2 + 1] as u16) << 8);
|
||||
for y in 0..height {
|
||||
for x in 0..width {
|
||||
let price = (values[(y * width + x) * 2] as u16) | ((values[(y * width + x) * 2 + 1] as u16) << 8);
|
||||
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;
|
||||
for &price in &prices {
|
||||
if price > 0 {
|
||||
buyable_house_count += 1;
|
||||
}
|
||||
}
|
||||
City { prices, buyable_house_count }
|
||||
City { prices, buyable_house_count, width, height }
|
||||
}
|
||||
|
||||
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 {
|
||||
self.prices[y * SIZE + x]
|
||||
self.prices[y * self.width + x]
|
||||
}
|
||||
|
||||
pub fn is_house(&self, house: House) -> bool {
|
||||
|
@ -53,6 +57,13 @@ impl City {
|
|||
pub fn get_house_count(&self) -> usize {
|
||||
self.buyable_house_count
|
||||
}
|
||||
|
||||
pub fn width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
pub fn height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Eq, PartialEq, Hash, Copy, Clone)]
|
||||
|
@ -66,11 +77,11 @@ impl House {
|
|||
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 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 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}
|
||||
}
|
||||
}
|
||||
|
@ -117,15 +128,15 @@ pub struct HouseLayout<'a> {
|
|||
|
||||
impl<'a> HouseLayout<'a> {
|
||||
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 {
|
||||
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 {
|
||||
self.reachable[y * SIZE + x]
|
||||
self.reachable[y * self.city.width + x]
|
||||
}
|
||||
|
||||
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 {
|
||||
let range_rect = house.range_rectangle();
|
||||
let range_rect = house.range_rectangle(self.city);
|
||||
for y in range_rect.top..=range_rect.bottom {
|
||||
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) {
|
||||
self.reachable_houses += 1;
|
||||
|
@ -152,10 +163,10 @@ impl<'a> HouseLayout<'a> {
|
|||
pub fn remove_house(&mut self, index: usize) {
|
||||
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 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;
|
||||
|
||||
|
@ -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> {
|
||||
let mut reachable = vec![false; SIZE * SIZE];
|
||||
let mut reachable = vec![false; city.width() * city.height()];
|
||||
let mut price = 0u32;
|
||||
|
||||
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 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;
|
||||
}
|
||||
|
||||
for y in 0..SIZE {
|
||||
for x in 0..SIZE {
|
||||
if !reachable[y * SIZE + x] && city.prices[y * SIZE + x] > 0 {
|
||||
for y in 0..city.height {
|
||||
for x in 0..city.width {
|
||||
if !reachable[y * city.width + x] && city.prices[y * city.width + x] > 0 {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
@ -217,35 +228,35 @@ pub fn is_valid(city: &City, houses: &Vec<House>) -> Option<u32> {
|
|||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
//use super::*;
|
||||
|
||||
#[test]
|
||||
fn house_rectangle_at_min() {
|
||||
let house = House::new(0, 0);
|
||||
let rect = house.range_rectangle();
|
||||
assert_eq!(rect.top, 0);
|
||||
assert_eq!(rect.left, 0);
|
||||
assert_eq!(rect.right, HOUSE_RANGE);
|
||||
assert_eq!(rect.bottom, HOUSE_RANGE);
|
||||
}
|
||||
//#[test]
|
||||
//fn house_rectangle_at_min() {
|
||||
// let house = House::new(0, 0);
|
||||
// let rect = house.range_rectangle();
|
||||
// assert_eq!(rect.top, 0);
|
||||
// assert_eq!(rect.left, 0);
|
||||
// assert_eq!(rect.right, HOUSE_RANGE);
|
||||
// assert_eq!(rect.bottom, HOUSE_RANGE);
|
||||
//}
|
||||
|
||||
#[test]
|
||||
fn house_rectangle_at_max() {
|
||||
let house = House::new(SIZE - 1, SIZE - 1);
|
||||
let rect = house.range_rectangle();
|
||||
assert_eq!(rect.top, SIZE - 1 - HOUSE_RANGE);
|
||||
assert_eq!(rect.left, SIZE - 1 - HOUSE_RANGE);
|
||||
assert_eq!(rect.right, SIZE - 1);
|
||||
assert_eq!(rect.bottom, SIZE - 1);
|
||||
}
|
||||
//#[test]
|
||||
//fn house_rectangle_at_max() {
|
||||
// let house = House::new(SIZE - 1, SIZE - 1);
|
||||
// let rect = house.range_rectangle();
|
||||
// assert_eq!(rect.top, SIZE - 1 - HOUSE_RANGE);
|
||||
// assert_eq!(rect.left, SIZE - 1 - HOUSE_RANGE);
|
||||
// assert_eq!(rect.right, SIZE - 1);
|
||||
// assert_eq!(rect.bottom, SIZE - 1);
|
||||
//}
|
||||
|
||||
#[test]
|
||||
fn house_rect_in_middle() {
|
||||
let house = House::new(SIZE / 2, SIZE / 2);
|
||||
let rect = house.range_rectangle();
|
||||
assert_eq!(rect.top, house.y - HOUSE_RANGE);
|
||||
assert_eq!(rect.left, house.x - HOUSE_RANGE);
|
||||
assert_eq!(rect.right, house.x + HOUSE_RANGE);
|
||||
assert_eq!(rect.bottom, house.y + HOUSE_RANGE);
|
||||
}
|
||||
//#[test]
|
||||
//fn house_rect_in_middle() {
|
||||
// let house = House::new(SIZE / 2, SIZE / 2);
|
||||
// let rect = house.range_rectangle();
|
||||
// assert_eq!(rect.top, house.y - HOUSE_RANGE);
|
||||
// assert_eq!(rect.left, house.x - HOUSE_RANGE);
|
||||
// assert_eq!(rect.right, house.x + HOUSE_RANGE);
|
||||
// assert_eq!(rect.bottom, house.y + HOUSE_RANGE);
|
||||
//}
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use db::{LayoutDB, SavedLayout};
|
||||
use city::{City, House, SIZE};
|
||||
use city::{City, House};
|
||||
use itertools::Itertools;
|
||||
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");
|
||||
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!("Building a transposed city...");
|
||||
|
@ -61,16 +61,16 @@ fn main() {
|
|||
}
|
||||
|
||||
fn transpose_city(city: &City) -> City {
|
||||
let mut transposed_prices = vec![0u16; SIZE * SIZE];
|
||||
for y in 0..SIZE {
|
||||
for x in 0..SIZE {
|
||||
let mut transposed_prices = vec![0u16; city.width() * city.height()];
|
||||
for y in 0..city.height() {
|
||||
for x in 0..city.width() {
|
||||
// Sorry, cache! Not worth optimizing with blocks,
|
||||
// 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 {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::city;
|
||||
use crate::db::{LayoutDB, SavedLayout, MergeLowerBound};
|
||||
use crate::city::{City, House, SIZE};
|
||||
use crate::city::{City, House};
|
||||
use itertools::Itertools;
|
||||
use itertools::iproduct;
|
||||
use std::collections::{VecDeque, HashMap};
|
||||
|
@ -9,12 +9,12 @@ use std::collections::vec_deque::Iter;
|
|||
struct LeftState<'a> {
|
||||
layout: &'a SavedLayout,
|
||||
sorted_houses: Vec<House>,
|
||||
line: LeftLine
|
||||
line: LeftLine<'a>
|
||||
}
|
||||
|
||||
struct RightState<'a> {
|
||||
layout: &'a SavedLayout,
|
||||
line: RightLine
|
||||
line: RightLine<'a>
|
||||
}
|
||||
|
||||
pub struct CompatibilityCache {
|
||||
|
@ -73,7 +73,7 @@ pub fn create_new_best_combination(city: &City, left_layouts: &Vec<SavedLayout>,
|
|||
lefts.push(LeftState {
|
||||
layout: &left_layout,
|
||||
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 line = RightLine::new();
|
||||
let mut line = RightLine::new(&city);
|
||||
// Make sure that we include all houses initially
|
||||
while let Some(house) = sorted_houses.pop() {
|
||||
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" };
|
||||
|
||||
// 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);
|
||||
|
||||
// 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 {
|
||||
for y in 0..SIZE {
|
||||
for y in 0..city.height() {
|
||||
let max_left_covered_x = left.get_max_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
|
||||
}
|
||||
|
||||
struct LeftLine {
|
||||
struct LeftLine<'a> {
|
||||
covers: Vec<usize>,
|
||||
houses: Vec<House>,
|
||||
price: u32,
|
||||
last_update_x: usize
|
||||
last_update_x: usize,
|
||||
city: &'a City
|
||||
}
|
||||
|
||||
struct RightLine {
|
||||
struct RightLine<'a> {
|
||||
covers: Vec<usize>,
|
||||
houses: VecDeque<House>,
|
||||
price: u32,
|
||||
last_update_x: usize
|
||||
last_update_x: usize,
|
||||
city: &'a City
|
||||
}
|
||||
|
||||
impl LeftLine {
|
||||
pub fn new() -> Self {
|
||||
impl<'a> LeftLine<'a> {
|
||||
pub fn new(city: &'a City) -> Self {
|
||||
// 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();
|
||||
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) {
|
||||
let range_rect = house.range_rectangle();
|
||||
let range_rect = house.range_rectangle(city);
|
||||
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);
|
||||
|
@ -276,16 +278,16 @@ impl LeftLine {
|
|||
}
|
||||
}
|
||||
|
||||
impl RightLine {
|
||||
pub fn new() -> Self {
|
||||
let covers = vec![usize::MAX; SIZE];
|
||||
impl<'a> RightLine<'a> {
|
||||
pub fn new(city: &'a City) -> Self {
|
||||
let covers = vec![usize::MAX; city.height()];
|
||||
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) {
|
||||
// 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 {
|
||||
self.covers[y] = self.covers[y].min(range_rect.left);
|
||||
}
|
||||
|
@ -300,7 +302,7 @@ impl RightLine {
|
|||
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();
|
||||
let removed_rect = removed_house.range_rectangle(city);
|
||||
|
||||
// Remove the now-outdated distances around the removed house
|
||||
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
|
||||
// intersects the removed area
|
||||
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 {
|
||||
house_rect.top..=removed_rect.bottom
|
||||
} else {
|
||||
|
@ -331,7 +333,7 @@ impl RightLine {
|
|||
}
|
||||
|
||||
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 {
|
||||
|
|
|
@ -26,7 +26,7 @@ fn main() {
|
|||
let mut db = LayoutDB::from_file("layouts.sqlite").expect("Failed to load the DB");
|
||||
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());
|
||||
|
||||
const MIN_WEIGHT_SCORE: f64 = 540000.;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::HashSet;
|
||||
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;
|
||||
|
||||
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.
|
||||
let mut covered_rect: Option<Rectangle> = None;
|
||||
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 x in range_rect.left..=range_rect.right {
|
||||
// We count how many rectangles of houses contain this xy position.
|
||||
let mut rectangles_containing_count = 0;
|
||||
for house in houses {
|
||||
let rect = house.range_rectangle();
|
||||
let rect = house.range_rectangle(layout.city);
|
||||
if rect.is_inside(x, y) {
|
||||
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 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 right = (covered_rect.right + width_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(layout.city.width() - 1);
|
||||
|
||||
if top > bottom || left > right {
|
||||
// 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.
|
||||
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 x in range_rect.left..=range_rect.right {
|
||||
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 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 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 {
|
||||
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 house2 = layout.houses()[house2_index];
|
||||
|
||||
let rect1 = house1.range_rectangle();
|
||||
let rect2 = house2.range_rectangle();
|
||||
let rect1 = house1.range_rectangle(layout.city);
|
||||
let rect2 = house2.range_rectangle(layout.city);
|
||||
|
||||
let top1 = rect1.top.min(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 margin_bottom = bottom1 + 1..=bottom2;
|
||||
|
||||
let mut top_distance = SIZE;
|
||||
let mut bottom_distance = SIZE;
|
||||
let mut right_distance = SIZE;
|
||||
let mut left_distance = SIZE;
|
||||
let mut top_distance = usize::MAX;
|
||||
let mut bottom_distance = usize::MAX;
|
||||
let mut right_distance = usize::MAX;
|
||||
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),
|
||||
// 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
|
||||
assert_ne!(top_distance, SIZE);
|
||||
assert_ne!(top_distance, usize::MAX);
|
||||
|
||||
Some(MoveDistances {
|
||||
left: left_distance,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use rand::Rng;
|
||||
use crate::city::{SIZE, House, HouseLayout, City};
|
||||
use crate::city::{House, HouseLayout, City};
|
||||
use rand::prelude::*;
|
||||
use crate::db::{LayoutDB, SavedLayout};
|
||||
use crate::city;
|
||||
|
@ -11,8 +11,8 @@ use rand::distributions::WeightedIndex;
|
|||
pub fn populate_random(layout: &mut HouseLayout, rng: &mut StdRng) {
|
||||
loop {
|
||||
loop {
|
||||
let x = rng.gen_range(0..SIZE);
|
||||
let y = rng.gen_range(0..SIZE);
|
||||
let x = rng.gen_range(0..layout.city.width());
|
||||
let y = rng.gen_range(0..layout.city.height());
|
||||
let house = House::new(x, y);
|
||||
if layout.city.is_house_xy(x, y) && !layout.is_covered(house) {
|
||||
layout.add_house(house);
|
||||
|
@ -59,8 +59,8 @@ pub fn populate_using_db(layout: &mut HouseLayout, mut rng: &mut StdRng, db: &La
|
|||
}
|
||||
} else {
|
||||
loop {
|
||||
let x = rng.gen_range(0..SIZE);
|
||||
let y = rng.gen_range(0..SIZE);
|
||||
let x = rng.gen_range(0..layout.city.width());
|
||||
let y = rng.gen_range(0..layout.city.height());
|
||||
let house = House::new(x, y);
|
||||
if layout.city.is_house_xy(x, y) && !layout.is_covered(house) {
|
||||
layout.add_house(house);
|
||||
|
|
Loading…
Reference in a new issue