use rand::Rng; use crate::city::{House, HouseLayout, City}; use rand::prelude::*; use crate::db::{SqliteLayoutDB, SavedLayout, LayoutDB}; use crate::city; use std::collections::HashMap; use std::ops::Add; use itertools::Itertools; use rand::distributions::WeightedIndex; pub fn populate_random(layout: &mut HouseLayout, rng: &mut StdRng) { loop { loop { 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); break; } } if layout.is_valid() { break; } } } pub fn build_house_probabilities(city: &City, db: &TDB, min_score: f64, max_score: f64) -> (WeightedIndex, Vec){ let mut counts: HashMap = HashMap::new(); for layout in db.layouts() { let price = city::get_price(&city, layout.houses()) as f64; let value_range = max_score - min_score; let value = 1. - ((price - min_score) / value_range).max(0.).min(1.); for house in layout.houses() { *counts.entry(*house).or_default() += value; } } let houses: Vec<_> = counts.into_iter().filter(|(house, price)| *price != 0.).collect(); let index = WeightedIndex::new(houses.iter().map(|(house, price)| price)).unwrap(); (index, houses.iter().map(|(house, _)| *house).collect()) } pub fn populate_using_db(layout: &mut HouseLayout, mut rng: &mut StdRng, db: &TDB, min_score: f64, max_score: f64, db_probability: f64) { let (mut index, houses) = build_house_probabilities(&layout.city, db, min_score, max_score); loop { if rng.gen::() < db_probability { // TODO: Test without allowing buying covered tiles let house = houses[index.sample(&mut rng)]; layout.add_house(house); if layout.is_valid() { break; } } else { loop { 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); break; } } if layout.is_valid() { break; } } } } pub fn populate_from_saved_layout(layout: &mut HouseLayout, saved_layout: &SavedLayout) { for house in saved_layout.houses() { layout.add_house(*house); } }