parent
27577d0647
commit
230a368660
@ -0,0 +1,227 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
use std::error::Error;
|
||||
use std::hash::Hash;
|
||||
use std::io::{self, Read};
|
||||
use std::str::FromStr;
|
||||
|
||||
fn main() -> Result<(), Box<Error>> {
|
||||
let mut input = String::new();
|
||||
io::stdin().read_to_string(&mut input)?;
|
||||
|
||||
let output = solve(&input)?;
|
||||
println!("{}", output);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn solve(input: &str) -> Result<String, Box<Error>> {
|
||||
let coords = Coords::from_str(input)?;
|
||||
|
||||
let min_x = coords.0.iter().map(|c| c.x).min().unwrap();
|
||||
let max_x = coords.0.iter().map(|c| c.x).max().unwrap();
|
||||
let min_y = coords.0.iter().map(|c| c.y).min().unwrap();
|
||||
let max_y = coords.0.iter().map(|c| c.y).max().unwrap();
|
||||
let top_left = Coord { x: min_x, y: min_y };
|
||||
let bottom_right = Coord { x: max_x, y: max_y };
|
||||
|
||||
let coord_names: HashMap<_, _> = coords
|
||||
.0
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, c)| (c, (i + 65) as u8 as char))
|
||||
.collect();
|
||||
|
||||
let grid = Grid::new(top_left, bottom_right, |coord| {
|
||||
coords
|
||||
.closest(*coord)
|
||||
.and_then(|closest| coord_names.get(&closest))
|
||||
});
|
||||
let edges: HashSet<_> = grid.edges().iter().flat_map(|&x| x).collect();
|
||||
|
||||
let mut area_sizes = HashMap::new();
|
||||
grid.locations
|
||||
.values()
|
||||
.flat_map(|x| x)
|
||||
.filter(|x| !edges.contains(x))
|
||||
.for_each(|x| {
|
||||
let count = area_sizes.entry(x).or_insert(0);
|
||||
*count += 1;
|
||||
});
|
||||
|
||||
let max_area = area_sizes.iter().map(|(_, v)| v).max().unwrap();
|
||||
Ok(max_area.to_string())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_solve() {
|
||||
let input = r"
|
||||
1, 1
|
||||
1, 6
|
||||
8, 3
|
||||
3, 4
|
||||
5, 5
|
||||
8, 9
|
||||
";
|
||||
|
||||
let output = solve(&input).unwrap();
|
||||
assert_eq!(output, "17".to_string());
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Grid<T> {
|
||||
top_left: Coord,
|
||||
bottom_right: Coord,
|
||||
locations: HashMap<Coord, T>,
|
||||
}
|
||||
|
||||
impl<T> Grid<T> {
|
||||
fn new<C: Into<Coord>, F: Fn(&Coord) -> T>(top_left: C, bottom_right: C, f: F) -> Self {
|
||||
let top_left = top_left.into();
|
||||
let bottom_right = bottom_right.into();
|
||||
let mut locations = HashMap::new();
|
||||
|
||||
for coord in top_left.grid(&bottom_right) {
|
||||
locations.insert(coord, f(&coord));
|
||||
}
|
||||
|
||||
Grid {
|
||||
top_left,
|
||||
bottom_right,
|
||||
locations,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Eq + Hash> Grid<T> {
|
||||
fn edges(&self) -> HashSet<&T> {
|
||||
let mut edges = HashSet::new();
|
||||
|
||||
for x in self.top_left.x..=self.bottom_right.x {
|
||||
for &y in &[self.top_left.y, self.bottom_right.y] {
|
||||
if let Some(t) = self.locations.get(&Coord { x, y }) {
|
||||
edges.insert(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for y in self.top_left.y..=self.bottom_right.y {
|
||||
for &x in &[self.top_left.x, self.bottom_right.x] {
|
||||
if let Some(t) = self.locations.get(&Coord { x, y }) {
|
||||
edges.insert(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
edges
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edges() {
|
||||
let top_left = Coord { x: 0, y: 0 };
|
||||
let bottom_right = Coord { x: 2, y: 2 };
|
||||
let grid = Grid::new(top_left, bottom_right, |coord| coord.y * 3 + coord.x);
|
||||
let expected: HashSet<_> = vec![0, 1, 2, 3, 5, 6, 7, 8]
|
||||
.iter()
|
||||
.map(|&x| x as isize)
|
||||
.collect();
|
||||
assert_eq!(grid.edges(), expected.iter().collect());
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Coords(Vec<Coord>);
|
||||
|
||||
impl Coords {
|
||||
fn closest<C: Into<Coord>>(&self, c: C) -> Option<Coord> {
|
||||
let c = c.into();
|
||||
|
||||
let mut distances = HashMap::new();
|
||||
for coord in &self.0 {
|
||||
let distance = coord.distance(c);
|
||||
let v = distances.entry(distance).or_insert_with(Vec::new);
|
||||
v.push(coord);
|
||||
}
|
||||
|
||||
let (_, closest_coords) = distances.iter().min_by_key(|(&k, _)| k)?;
|
||||
if closest_coords.len() == 1 {
|
||||
Some(*closest_coords[0])
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_closest() {
|
||||
let coords = Coords::from_str(
|
||||
r"
|
||||
1, 1
|
||||
1, 6
|
||||
8, 3
|
||||
3, 4
|
||||
5, 5
|
||||
8, 9
|
||||
",
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(coords.closest((0, 0)), Some(Coord::from((1, 1))));
|
||||
assert_eq!(coords.closest((3, 2)), Some(Coord::from((3, 4))));
|
||||
assert_eq!(coords.closest((5, 0)), None);
|
||||
assert_eq!(coords.closest((0, 4)), None);
|
||||
}
|
||||
|
||||
impl FromStr for Coords {
|
||||
type Err = Box<Error>;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let coords = s
|
||||
.trim()
|
||||
.lines()
|
||||
.map(Coord::from_str)
|
||||
.collect::<Result<_, _>>()?;
|
||||
Ok(Coords(coords))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
struct Coord {
|
||||
x: isize,
|
||||
y: isize,
|
||||
}
|
||||
|
||||
impl Coord {
|
||||
fn distance<C: Into<Self>>(&self, other: C) -> isize {
|
||||
let other = other.into();
|
||||
(self.x - other.x).abs() + (self.y - other.y).abs()
|
||||
}
|
||||
|
||||
fn grid(&self, to: &Self) -> impl Iterator<Item = Coord> + '_ {
|
||||
let to = *to;
|
||||
(self.x..=to.x).flat_map(move |x| (self.y..=to.y).map(move |y| (x, y).into()))
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_distance() {
|
||||
let coord = Coord { x: 4, y: 3 };
|
||||
assert_eq!(coord.distance((1, 1)), 5);
|
||||
assert_eq!(coord.distance((8, 9)), 10);
|
||||
}
|
||||
|
||||
impl From<(isize, isize)> for Coord {
|
||||
fn from((x, y): (isize, isize)) -> Self {
|
||||
Coord { x, y }
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for Coord {
|
||||
type Err = Box<Error>;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let mut xy = s.split(", ");
|
||||
let x = xy.next().unwrap().parse()?;
|
||||
let y = xy.next().unwrap().parse()?;
|
||||
Ok(Coord { x, y })
|
||||
}
|
||||
}
|
Loading…
Reference in new issue