|
@ -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);
|
|
|
} |
|
|
//}
|
|
|
} |
|
|
} |
|
|