use rand::prelude::{StdRng, SliceRandom}; use rand::{SeedableRng, Rng, thread_rng}; use std::fmt; use std::fmt::Formatter; use std::collections::{HashMap, HashSet}; use city::{HouseLayout, City, House}; use crate::db::SqliteLayoutDB; use crate::population::{build_house_probabilities, populate_from_saved_layout}; use itertools::Itertools; mod optimization; mod population; mod city; mod db; enum RunType { GenNew, TryImproveBest } fn main() { let mut db = SqliteLayoutDB::from_file("layouts.sqlite", false).expect("Failed to load the DB"); eprintln!("Loaded the DB, {} stored layouts", db.layouts().len()); 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 = 530000.; const MAX_WEIGHT_SCORE: f64 = 540000.; const DB_CHOICE_PROBABILITY: f64 = 0.99; const START_WITH_MERGE: bool = false; //let best_layouts: Vec<_> = db.layouts().iter() // .sorted_by(|x, y| city::get_price(&city, x.houses()).cmp(&city::get_price(&city, y.houses()))) // .take_while(|x| city::get_price(&city, x.houses()) < 535000) // .map(|x| x.clone()) // .collect(); //if let Some(best_layout) = db.layouts().iter() // .sorted_by(|x, y| city::get_price(&city, x.houses()).cmp(&city::get_price(&city, y.houses()))) // .next() { // eprintln!("Printing best layout, ID {}, price {}", best_layout.id(), city::get_price(&city, best_layout.houses())); // print_houses(best_layout.houses()); //} let mut best_price: Option = None; //for best_layout in best_layouts { loop { let seed: u64 = thread_rng().gen(); eprintln!("Starting seed {}", seed); let mut rng = StdRng::seed_from_u64(seed); let mut layout = HouseLayout::new(&city); //eprintln!("Starting random population..."); //population::populate_random(&mut layout, &mut rng); eprintln!("Starting random weighted population, using DB ({}-{} {})...", MIN_WEIGHT_SCORE, MAX_WEIGHT_SCORE, DB_CHOICE_PROBABILITY); population::populate_using_db(&mut layout, &mut rng, &db, MIN_WEIGHT_SCORE, MAX_WEIGHT_SCORE, DB_CHOICE_PROBABILITY); eprintln!("Finished random init, price: {}, houses: {}", layout.price(), layout.houses().len()); //populate_from_saved_layout(&mut layout, &best_layout); //eprintln!("Finished loading DB layout ID {}, price: {}, houses: {}", best_layout.id(), layout.price(), layout.houses().len()); let improved = optimization::iterate_improvements(&mut layout, &mut rng, true, START_WITH_MERGE); dump_layout(&layout, &mut best_price, seed); //if improved { db.add_layout(&layout.houses(), true).expect("Failed to insert into DB"); //} } } fn print_houses(houses: &Vec) { println!("{}", houses.len()); for house in houses { println!("{} {}", house.y, house.x); } } fn dump_layout(layout: &HouseLayout, best_price: &mut Option, seed: u64) { let price = layout.price(); if best_price.is_none() || price < best_price.unwrap() { *best_price = Some(price); eprintln!("Printing {} - new best", price); println!("New best!"); println!("Price {}, seed {}", price, seed); print_houses(&layout.houses()); println!(); } else { eprintln!("Printing {}", price); println!("Price {}, seed {}", price, seed); print_houses(&layout.houses()); println!(); } }