From 230a36866030dc886530b4542b7aeeb5dd940c8e Mon Sep 17 00:00:00 2001 From: Alpha Chen Date: Thu, 6 Dec 2018 16:51:55 -0800 Subject: [PATCH] [2018][rust][06.0] --- 2018/rust/src/bin/day_06.rs | 227 ++++++++++++++++++++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 2018/rust/src/bin/day_06.rs diff --git a/2018/rust/src/bin/day_06.rs b/2018/rust/src/bin/day_06.rs new file mode 100644 index 0000000..236f739 --- /dev/null +++ b/2018/rust/src/bin/day_06.rs @@ -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> { + let mut input = String::new(); + io::stdin().read_to_string(&mut input)?; + + let output = solve(&input)?; + println!("{}", output); + + Ok(()) +} + +fn solve(input: &str) -> Result> { + 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 { + top_left: Coord, + bottom_right: Coord, + locations: HashMap, +} + +impl Grid { + fn new, 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 Grid { + 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); + +impl Coords { + fn closest>(&self, c: C) -> Option { + 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; + + fn from_str(s: &str) -> Result { + let coords = s + .trim() + .lines() + .map(Coord::from_str) + .collect::>()?; + Ok(Coords(coords)) + } +} + +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +struct Coord { + x: isize, + y: isize, +} + +impl Coord { + fn distance>(&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 + '_ { + 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; + + fn from_str(s: &str) -> Result { + let mut xy = s.split(", "); + let x = xy.next().unwrap().parse()?; + let y = xy.next().unwrap().parse()?; + Ok(Coord { x, y }) + } +}