From 9a0f24d6bb882da46b3805ae35163267bf0e7ed4 Mon Sep 17 00:00:00 2001 From: Bert Peters Date: Mon, 3 Dec 2018 10:41:38 +0100 Subject: [PATCH] Implement day 3. Wasted way too much trying to do this cleverly. --- 2018/Cargo.toml | 1 + 2018/src/day03.rs | 130 ++++++++++++++++++++++++++++++++++++++++++++++ 2018/src/main.rs | 3 ++ 3 files changed, 134 insertions(+) create mode 100644 2018/src/day03.rs diff --git a/2018/Cargo.toml b/2018/Cargo.toml index a6afa63..87e41a0 100644 --- a/2018/Cargo.toml +++ b/2018/Cargo.toml @@ -5,3 +5,4 @@ authors = ["Bert Peters "] [dependencies] clap = "2.32" +regex = "1.1.0" diff --git a/2018/src/day03.rs b/2018/src/day03.rs new file mode 100644 index 0000000..2be5b8f --- /dev/null +++ b/2018/src/day03.rs @@ -0,0 +1,130 @@ +use std::collections::HashMap; +use std::collections::HashSet; +use std::io; +use std::io::BufRead; +use std::ops::Range; + +use common; +use regex; + +#[derive(Copy, Clone, Debug)] +struct Claim { + x: usize, + y: usize, + width: usize, + height: usize, +} + +impl Claim { + + pub fn xrange(&self) -> Range { + self.x..(self.x + self.width) + } + + pub fn yrange(&self) -> Range { + self.y..(self.y + self.height) + } +} + +#[derive(Default)] +pub struct Day03 { + claims: Vec +} + + +impl Day03 { + pub fn new() -> Day03 { + Default::default() + } + + fn read_claims(&mut self, input: &mut io::Read) { + let reader = io::BufReader::new(input); + self.claims.clear(); + + let matcher = regex::Regex::new(r"^#(\d+) @ (\d+),(\d+): (\d+)x(\d+)$").unwrap(); + + for line in reader.lines() { + let line = line.unwrap(); + let matched = matcher.captures(&line).unwrap(); + + let claim = Claim{ + x: matched.get(2).unwrap().as_str().parse().unwrap(), + y: matched.get(3).unwrap().as_str().parse().unwrap(), + width: matched.get(4).unwrap().as_str().parse().unwrap(), + height: matched.get(5).unwrap().as_str().parse().unwrap(), + }; + self.claims.push(claim); + } + } +} + + +impl common::Solution for Day03 { + fn part1(&mut self, input: &mut io::Read) -> String { + self.read_claims(input); + let mut claim_map = HashMap::new(); + + for claim in &self.claims { + for x in claim.xrange() { + for y in claim.yrange() { + *claim_map.entry((x, y)).or_insert(0) += 1; + } + } + } + + let multi_claim = claim_map.values() + .filter(|&&x| x > 1) + .count(); + + format!("{}", multi_claim) + } + + fn part2(&mut self, input: &mut io::Read) -> String { + self.read_claims(input); + let mut claim_map: HashMap<(usize, usize), Vec> = HashMap::new(); + let mut overlaps: Vec> = Vec::new(); + overlaps.resize(self.claims.len(), HashSet::new()); + + for (idx, claim) in self.claims.iter().enumerate() { + for x in claim.xrange() { + for y in claim.yrange() { + let entry = claim_map.entry((x, y)).or_insert(Vec::new()); + for claim in entry.iter() { + overlaps[*claim].insert(idx); + overlaps[idx].insert(*claim); + } + + &entry.push(idx); + } + } + } + + let uncontested = overlaps.iter().position(|x| x.is_empty()).unwrap(); + format!("{}", uncontested + 1) + } +} + +#[cfg(test)] +mod tests { + use common::Solution; + + use super::*; + + const SAMPLE_INPUT: &[u8] = b"#1 @ 1,3: 4x4 +#2 @ 3,1: 4x4 +#3 @ 5,5: 2x2"; + + #[test] + fn sample_part1() { + let mut instance = Day03::new(); + let result = instance.part1(&mut SAMPLE_INPUT); + assert_eq!("4", result); + } + + #[test] + fn sample_part2() { + let mut instance = Day03::new(); + let result = instance.part2(&mut SAMPLE_INPUT); + assert_eq!("3", result); + } +} diff --git a/2018/src/main.rs b/2018/src/main.rs index 3032044..1c9e31c 100644 --- a/2018/src/main.rs +++ b/2018/src/main.rs @@ -1,4 +1,5 @@ extern crate clap; +extern crate regex; use clap::{Arg, App}; use std::fs; use std::io; @@ -6,11 +7,13 @@ use std::io; pub mod common; pub mod day01; pub mod day02; +pub mod day03; fn get_impl(day: &str) -> Box { match day.parse() { Ok(1) => Box::new(day01::Day01::new()), Ok(2) => Box::new(day02::Day02::new()), + Ok(3) => Box::new(day03::Day03::new()), Ok(val) => panic!("Unimplemented day {}", val), _ => panic!("Invalid number"), }