From 7b04f00291cb2068f306191a6ad66c777696825d Mon Sep 17 00:00:00 2001 From: Wesley Moore Date: Wed, 12 Dec 2018 21:08:54 +1100 Subject: [PATCH] Add day 6 2018 part 1 solution --- 2018/Cargo.toml | 1 + 2018/src/bin/day6.rs | 135 +++++++++++++++++++++++++++++++++++++++---- 2 files changed, 126 insertions(+), 10 deletions(-) diff --git a/2018/Cargo.toml b/2018/Cargo.toml index ba10ce8..98138c0 100644 --- a/2018/Cargo.toml +++ b/2018/Cargo.toml @@ -2,6 +2,7 @@ name = "advent-of-code" version = "0.1.0" authors = ["Wesley Moore "] +edition = "2018" [dependencies] chrono = "0.4.6" diff --git a/2018/src/bin/day6.rs b/2018/src/bin/day6.rs index 4ba37b2..1cb4232 100644 --- a/2018/src/bin/day6.rs +++ b/2018/src/bin/day6.rs @@ -2,12 +2,112 @@ extern crate lazy_static; extern crate regex; +use std::collections::{HashMap, HashSet}; use std::fs; use regex::Regex; #[derive(Debug)] -struct Coordinate(i32, i32); +struct Coordinate { + x: u32, + y: u32, +} + +impl Coordinate { + fn distance_to(&self, other: &Coordinate) -> u32 { + ((other.x as i32 - self.x as i32).abs() + (other.y as i32 - self.y as i32).abs()) as u32 + } +} + +#[derive(Debug, Clone)] +enum Claim { + Unclaimed, + Claimed { index: usize, distance: u32 }, + Tied { distance: u32 }, +} + +struct Grid { + grid: Vec, + width: usize, + height: usize, +} + +impl Grid { + fn new(width: usize, height: usize) -> Self { + Self { + grid: vec![Claim::Unclaimed; width * height], + width, + height, + } + } + + fn claim(&mut self, index: usize, coord: &Coordinate) { + // loop through the grid, calculate the distance to each point, if it's unclaimed or the + // distance is shorter then claim it. + for (current_index, claim) in self.grid.iter_mut().enumerate() { + let current_coord = index_to_coord(current_index, self.width); + let distance = coord.distance_to(¤t_coord); + + match claim { + Claim::Unclaimed => *claim = Claim::Claimed { index, distance }, + Claim::Claimed { + distance: claimed_distance, + .. + } if *claimed_distance > distance => *claim = Claim::Claimed { index, distance }, + Claim::Claimed { + distance: claimed_distance, + .. + } if *claimed_distance == distance => *claim = Claim::Tied { distance }, + Claim::Tied { + distance: tied_distance, + } if distance < *tied_distance => *claim = Claim::Claimed { index, distance }, + _ => {} + } + } + } + + fn largest_claimed_area(&self) -> u32 { + let areas = self.grid.iter().fold(HashMap::new(), |mut areas, claim| { + if let Claim::Claimed { index, .. } = claim { + let area = areas.entry(index).or_insert(0u32); + *area += 1 + } + + areas + }); + + // Exclude indexes that touch the edges as they will be infinite + let mut exclude = HashSet::new(); + for x in 0..self.width { + if let Claim::Claimed { index, .. } = self.grid[x] { + exclude.insert(index); + } + if let Claim::Claimed { index, .. } = self.grid[self.width * (self.height - 1) + x] { + exclude.insert(index); + } + } + for y in 1..self.height - 1 { + if let Claim::Claimed { index, .. } = self.grid[y * self.width] { + exclude.insert(index); + } + if let Claim::Claimed { index, .. } = self.grid[y * self.width + self.width - 1] { + exclude.insert(index); + } + } + + *areas + .iter() + .filter_map(|(index, area)| { + if exclude.contains(index) { + None + } else { + Some(area) + } + }) + .max() + .unwrap() + } +} fn main() { let input = fs::read_to_string("input/day6.txt").expect("input"); @@ -23,22 +123,28 @@ fn main() { fn part1(coordinates: &[Coordinate]) { let max = furthest_coord(coordinates); - let grid = vec![None, max.0 * max.1]; + let mut grid = Grid::new(max.x as usize, max.y as usize); - // Now fill the grid with the coords... + // Claim closest locations for each coord + for (index, coord) in coordinates.iter().enumerate() { + grid.claim(index, &coord); + } + // Find the one with the most claimed area + let area = grid.largest_claimed_area(); + println!("Part 1 = {}", area); } fn furthest_coord(coordinates: &[Coordinate]) -> Coordinate { // There are no negative coords, so assume origin at 0,0 - let mut max = Coordinate(0, 0); - for Coordinate(x, y) in coordinates { - if *x > max.0 { - max.0= *x; + let mut max = Coordinate { x: 0, y: 0 }; + for Coordinate { x, y } in coordinates { + if *x > max.x { + max.x = *x; } - if *y > max.1 { - max.1 = *y; + if *y > max.y { + max.y = *y; } } @@ -51,5 +157,14 @@ fn parse_coord(line: &str) -> Option { } let captures = RE.captures(line)?; - Some(Coordinate(captures[1].parse().ok()?, captures[2].parse().ok()?)) + Some(Coordinate { + x: captures[1].parse().ok()?, + y: captures[2].parse().ok()?, + }) +} + +fn index_to_coord(index: usize, width: usize) -> Coordinate { + let x = (index % width) as u32; + let y = (index / width) as u32; + Coordinate { x, y } }