|
@ -15,7 +15,7 @@ impl City { |
|
|
|
|
|
|
|
|
for y in 0..SIZE { |
|
|
for y in 0..SIZE { |
|
|
for x in 0..SIZE { |
|
|
for x in 0..SIZE { |
|
|
let price = (values[(y * SIZE + x) * 2] as u16) | ((values[(y * SIZE + x) * 2] as u16) << 8); |
|
|
let price = (values[(y * SIZE + x) * 2] as u16) | ((values[(y * SIZE + x) * 2 + 1] as u16) << 8); |
|
|
prices.push(price); |
|
|
prices.push(price); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
@ -69,6 +69,7 @@ impl House { |
|
|
fn main() { |
|
|
fn main() { |
|
|
let city = City::read_from_file("01.in"); |
|
|
let city = City::read_from_file("01.in"); |
|
|
|
|
|
|
|
|
|
|
|
let mut best_price: Option<u32> = None; |
|
|
loop { |
|
|
loop { |
|
|
let seed: u64 = thread_rng().gen(); |
|
|
let seed: u64 = thread_rng().gen(); |
|
|
eprintln!("Starting seed {}", seed); |
|
|
eprintln!("Starting seed {}", seed); |
|
@ -106,40 +107,71 @@ fn main() { |
|
|
break; |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
let mut price = get_price(&city, &houses); |
|
|
let mut price = get_price(&city, &houses); |
|
|
eprintln!("Finished randomized init, price: {}", price); |
|
|
eprintln!("Finished random init, price: {}", price); |
|
|
loop { |
|
|
|
|
|
|
|
|
const AROUND_RANGE: i32 = 50; |
|
|
|
|
|
const MAX_CANDIDATES: usize = 20; |
|
|
|
|
|
const MAX_FAILED_ITERATIONS: usize = 50; |
|
|
|
|
|
|
|
|
|
|
|
let mut failed_iterations = 0; |
|
|
|
|
|
while failed_iterations < MAX_FAILED_ITERATIONS { |
|
|
let house = &houses.choose(&mut rng).unwrap(); |
|
|
let house = &houses.choose(&mut rng).unwrap(); |
|
|
let mut new_candidate: Option<House> = None; |
|
|
let mut new_candidates = Vec::new(); |
|
|
for _ in 0..5000 { |
|
|
for delta_y in -AROUND_RANGE..=AROUND_RANGE { |
|
|
let delta_x = rng.gen_range(-50..=50); |
|
|
for delta_x in -AROUND_RANGE..=AROUND_RANGE { |
|
|
let delta_y = rng.gen_range(-50..=50); |
|
|
|
|
|
let new_x = (house.x as i32 + delta_x).max(0).min(SIZE as i32 - 1) as usize; |
|
|
let new_x = (house.x as i32 + delta_x).max(0).min(SIZE as i32 - 1) as usize; |
|
|
let new_y = (house.y as i32 + delta_y).max(0).min(SIZE as i32 - 1) as usize; |
|
|
let new_y = (house.y as i32 + delta_y).max(0).min(SIZE as i32 - 1) as usize; |
|
|
if city.is_house_xy(new_x, new_y) && city.get_price_xy(new_x, new_y) < city.get_price(&house) { |
|
|
if city.is_house_xy(new_x, new_y) && city.get_price_xy(new_x, new_y) < city.get_price(&house) { |
|
|
new_candidate = Some(House::new(new_x, new_y)); |
|
|
new_candidates.push(House::new(new_x, new_y)); |
|
|
break; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
if let Some(candidate) = new_candidate { |
|
|
new_candidates.sort_by(|a, b| city.get_price(&a).cmp(&city.get_price(&b))); |
|
|
eprint!("Found candidate..."); |
|
|
if new_candidates.len() == 0 { |
|
|
|
|
|
eprintln!("Did not find candidate"); |
|
|
|
|
|
} else { |
|
|
|
|
|
for (i, &candidate) in new_candidates.iter().enumerate() { |
|
|
|
|
|
if i > MAX_CANDIDATES { |
|
|
|
|
|
break; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
eprint!("Found candidate {}...", i); |
|
|
let mut new_houses: Vec<_> = houses.to_vec().into_iter().filter(|h| &h != house).collect(); |
|
|
let mut new_houses: Vec<_> = houses.to_vec().into_iter().filter(|h| &h != house).collect(); |
|
|
new_houses.push(candidate); |
|
|
new_houses.push(candidate); |
|
|
|
|
|
// TODO: This is_valid check could be way more efficient
|
|
|
if let Some(new_price) = is_valid(&city, &new_houses) { |
|
|
if let Some(new_price) = is_valid(&city, &new_houses) { |
|
|
let price_diff = new_price as i64 - price as i64; |
|
|
let price_diff = new_price as i64 - price as i64; |
|
|
eprintln!(" candidate is valid, price diff: {}.", price_diff); |
|
|
eprintln!(" candidate is valid, price diff: {}.", price_diff); |
|
|
eprintln!("New price: {}", new_price); |
|
|
eprintln!("Improved price: {}", new_price); |
|
|
price = new_price; |
|
|
price = new_price; |
|
|
houses = new_houses; |
|
|
houses = new_houses; |
|
|
print_houses(&houses); |
|
|
failed_iterations = 0; |
|
|
|
|
|
break; |
|
|
} else { |
|
|
} else { |
|
|
eprintln!(" candidate is invalid."); |
|
|
eprintln!(" candidate is invalid."); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
|
|
|
eprintln!("Did not find candidate"); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// Successful iterations always break
|
|
|
|
|
|
failed_iterations += 1; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if best_price.is_none() || price < best_price.unwrap() { |
|
|
|
|
|
best_price = Some(price); |
|
|
|
|
|
eprintln!("Finished randomization, price: {}, new best, printing", price); |
|
|
|
|
|
println!("Price {}, seed {}", price, seed); |
|
|
|
|
|
print_houses(&houses); |
|
|
|
|
|
println!(); |
|
|
|
|
|
} else { |
|
|
|
|
|
eprintln!("Finished randomization, price: {}, printing", price); |
|
|
|
|
|
println!("Price {}, seed {}", price, seed); |
|
|
|
|
|
print_houses(&houses); |
|
|
|
|
|
println!(); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|