2018-12-13 15:00:47 -05:00
|
|
|
use std::collections::HashMap;
|
2018-12-10 11:28:02 -05:00
|
|
|
use std::fs::File;
|
|
|
|
use std::io::{BufRead, BufReader};
|
|
|
|
|
|
|
|
struct Point {
|
|
|
|
x: usize,
|
|
|
|
y: usize,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Point {
|
|
|
|
fn distance(&self, other: &Point) -> i64 {
|
2019-01-03 22:06:21 -05:00
|
|
|
(self.x as i64 - other.x as i64).abs() + (self.y as i64 - other.y as i64).abs()
|
2018-12-10 11:28:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl std::fmt::Display for Point {
|
|
|
|
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
|
|
|
write!(f, "({}, {})", self.x, self.y)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-12-13 15:00:47 -05:00
|
|
|
fn calc_max_area(
|
|
|
|
points: &Vec<Point>,
|
|
|
|
min_x: usize,
|
|
|
|
min_y: usize,
|
|
|
|
max_x: usize,
|
|
|
|
max_y: usize,
|
|
|
|
) -> (u8, usize) {
|
2018-12-10 11:28:02 -05:00
|
|
|
let distances = calc_distances(points, min_x, min_y, max_x, max_y);
|
|
|
|
let mut areas: HashMap<u8, usize> = HashMap::new();
|
|
|
|
for i in min_x..=max_x {
|
|
|
|
for j in min_y..=max_y {
|
|
|
|
if distances[i][j] == 0 {
|
|
|
|
continue;
|
|
|
|
}
|
2018-12-13 15:00:47 -05:00
|
|
|
areas
|
|
|
|
.entry(distances[i][j])
|
|
|
|
.and_modify(|e| *e += 1)
|
|
|
|
.or_insert(1);
|
2018-12-10 11:28:02 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
let mut index = 0;
|
|
|
|
let mut max_area = 0;
|
|
|
|
let mut max_area_index = 0;
|
|
|
|
for _point in points.iter() {
|
|
|
|
index += 1;
|
|
|
|
let cur_area = areas.get(&index).unwrap();
|
|
|
|
if cur_area > &max_area {
|
|
|
|
max_area = *cur_area;
|
|
|
|
max_area_index = index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (key, value) in areas.iter() {
|
2018-12-13 15:00:47 -05:00
|
|
|
println!(
|
|
|
|
"{}: {} area {}",
|
|
|
|
key,
|
|
|
|
points.get((index - 1) as usize).unwrap(),
|
|
|
|
value
|
|
|
|
);
|
2018-12-10 11:28:02 -05:00
|
|
|
}
|
|
|
|
(max_area_index, max_area)
|
|
|
|
}
|
|
|
|
|
2018-12-13 15:00:47 -05:00
|
|
|
fn calc_distances(
|
|
|
|
points: &Vec<Point>,
|
|
|
|
min_x: usize,
|
|
|
|
min_y: usize,
|
|
|
|
max_x: usize,
|
|
|
|
max_y: usize,
|
|
|
|
) -> [[u8; 500]; 500] {
|
2018-12-10 11:28:02 -05:00
|
|
|
let mut distances = [[0u8; 500]; 500];
|
|
|
|
for i in min_x..=max_x {
|
|
|
|
for j in min_y..=max_y {
|
2018-12-13 15:00:47 -05:00
|
|
|
let cur_point = Point { x: i, y: j };
|
2018-12-10 11:28:02 -05:00
|
|
|
let mut min_dis = 500;
|
|
|
|
let mut found_dupe = false;
|
|
|
|
let mut min_index = 0;
|
|
|
|
let mut index = 0;
|
|
|
|
for point in points.iter() {
|
|
|
|
index += 1;
|
|
|
|
let dis = cur_point.distance(point);
|
|
|
|
if dis < min_dis {
|
|
|
|
min_dis = dis;
|
|
|
|
found_dupe = false;
|
|
|
|
min_index = index;
|
|
|
|
} else if dis == min_dis {
|
|
|
|
found_dupe = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if !found_dupe {
|
|
|
|
distances[i][j] = min_index;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
distances
|
|
|
|
}
|
|
|
|
|
|
|
|
fn calc_safe_zone(points: &Vec<Point>, threshold: i64) -> i64 {
|
|
|
|
let mut area = 0;
|
|
|
|
for i in 0..500 {
|
|
|
|
for j in 0..500 {
|
|
|
|
let point = Point { x: i, y: j };
|
|
|
|
let distance: i64 = points.iter().map(|p| p.distance(&point)).sum();
|
|
|
|
if distance < threshold {
|
|
|
|
area += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
area
|
|
|
|
}
|
|
|
|
|
2018-12-08 11:27:32 -05:00
|
|
|
fn main() {
|
2018-12-10 11:28:02 -05:00
|
|
|
let points: Vec<Point> = BufReader::new(File::open("input").unwrap())
|
|
|
|
.lines()
|
|
|
|
.map(|line| {
|
|
|
|
let points_str = line.unwrap();
|
|
|
|
let points_ints: Vec<usize> = points_str
|
|
|
|
.as_str()
|
|
|
|
.split(", ")
|
|
|
|
.map(|p| p.parse::<usize>().unwrap())
|
|
|
|
.collect();
|
|
|
|
Point {
|
|
|
|
x: *points_ints.get(0).unwrap(),
|
|
|
|
y: *points_ints.get(1).unwrap(),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
.collect();
|
|
|
|
let mut min_x = 500;
|
|
|
|
let mut min_y = 500;
|
|
|
|
let mut max_x = 0;
|
|
|
|
let mut max_y = 0;
|
|
|
|
for point in points.iter() {
|
2018-12-13 15:00:47 -05:00
|
|
|
if point.x < min_x {
|
|
|
|
min_x = point.x
|
|
|
|
};
|
|
|
|
if point.x > max_x {
|
|
|
|
max_x = point.x
|
|
|
|
};
|
|
|
|
if point.y < min_y {
|
|
|
|
min_y = point.y
|
|
|
|
};
|
|
|
|
if point.y > max_y {
|
|
|
|
max_y = point.y
|
|
|
|
};
|
2018-12-10 11:28:02 -05:00
|
|
|
}
|
|
|
|
let width = max_x - min_x;
|
|
|
|
let height = max_y - min_y;
|
|
|
|
println!("map size {}x{}", width, height);
|
|
|
|
let (max_area_point, max_area) = calc_max_area(&points, min_x, min_y, max_x, max_y);
|
|
|
|
let max_area_point_index = (max_area_point - 1) as usize;
|
2018-12-13 15:00:47 -05:00
|
|
|
println!(
|
|
|
|
"max area point {} {} is {}",
|
|
|
|
max_area_point,
|
|
|
|
points.get(max_area_point_index).unwrap(),
|
|
|
|
max_area
|
|
|
|
);
|
2018-12-10 11:28:02 -05:00
|
|
|
let safe_zone = calc_safe_zone(&points, 10000);
|
|
|
|
println!("safe zone area {}", safe_zone);
|
2018-12-08 11:27:32 -05:00
|
|
|
}
|
2019-01-03 22:06:21 -05:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_part_one() {
|
|
|
|
let points = vec![
|
|
|
|
Point { x: 1, y: 1 },
|
|
|
|
Point { x: 1, y: 6 },
|
|
|
|
Point { x: 8, y: 3 },
|
|
|
|
Point { x: 3, y: 4 },
|
|
|
|
Point { x: 5, y: 5 },
|
|
|
|
Point { x: 8, y: 9 },
|
|
|
|
];
|
|
|
|
let (max_area_point, max_area) = calc_max_area(&points, 1, 1, 8, 9);
|
|
|
|
assert_eq!(max_area, 17);
|
|
|
|
assert_eq!(max_area_point, 5);
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_part_two() {
|
|
|
|
let points = vec![
|
|
|
|
Point { x: 1, y: 1 },
|
|
|
|
Point { x: 1, y: 6 },
|
|
|
|
Point { x: 8, y: 3 },
|
|
|
|
Point { x: 3, y: 4 },
|
|
|
|
Point { x: 5, y: 5 },
|
|
|
|
Point { x: 8, y: 9 },
|
|
|
|
];
|
|
|
|
let safe_zone = calc_safe_zone(&points, 32);
|
|
|
|
assert_eq!(safe_zone, 16);
|
|
|
|
}
|
|
|
|
}
|