diff --git a/src/digit.rs b/src/digit.rs deleted file mode 100644 index 710a6c9..0000000 --- a/src/digit.rs +++ /dev/null @@ -1,31 +0,0 @@ -use std::convert; - -#[derive(Clone)] -pub struct Digit { - segments: Vec, -} - -impl convert::From<&str> for Digit { - fn from(s: &str) -> Self { - Digit { - segments: s.chars().collect(), - } - } -} - -impl Digit { - pub fn contains(&self, other: &Digit) -> bool { - other - .segments - .iter() - .all(|other_seg| self.segments.iter().any(|seg| other_seg == seg)) - } - - pub fn diff(&self, other: &Digit) -> String { - self.segments - .iter() - .copied() - .filter(|c| !other.segments.iter().any(|other_c| other_c == c)) - .collect() - } -} diff --git a/src/main.rs b/src/main.rs index c68ba9c..06c70b1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,37 +1,40 @@ -mod digit; -mod solver; +mod matrix; + +use matrix::Matrix; use std::fs::File; use std::io::{BufRead, BufReader}; use std::str; -fn merge_digits(digits: &[u8]) -> u16 { - digits - .iter() - .rev() - .copied() - .enumerate() - .map(|(i, d)| 10u16.pow(i as u32) * (d as u16)) - .sum() -} - fn process_lines(reader: impl BufRead) -> anyhow::Result { - let mut sum = 0u64; - for line_res in reader.lines() { - let line = line_res?; - let mut line_io = line.split('|'); - let input = line_io.next().expect("Malformed line input").trim(); - let output = line_io.next().expect("Malformed line output").trim(); - let input_vec: Vec<&str> = input.split_whitespace().collect(); - let key = solver::Key::try_from_input(&input_vec[..])?; - let number_vec = output - .split_whitespace() - .map(|digit| key.solve(digit)) + const WIDTH: usize = 100; + let mut raw_map: Vec = Vec::new(); + for line_result in reader.lines() { + let line = line_result?; + let mut row = line + .chars() + .map(|height_char| height_char.to_digit(10).map(|h| h as u8)) .collect::>>() - .expect("failed to process output digits"); - sum += merge_digits(&number_vec[..]) as u64; + .expect("invalid digit encountered"); + raw_map.append(&mut row); } - Ok(sum) + let map = Matrix::try_from_raw(&raw_map[..], WIDTH)?; + let mut risks = 0u64; + let map_height = map.get_height(); + for h in 0..map_height { + for w in 0..WIDTH { + let cave_height = map[(w, h)]; + let is_north_higher = 0 == h || cave_height < map[(w, h - 1)]; + let is_south_higher = map_height == h + 1 || cave_height < map[(w, h + 1)]; + let is_west_higher = 0 == w || cave_height < map[(w - 1, h)]; + let is_east_higher = WIDTH == w + 1 || cave_height < map[(w + 1, h)]; + if is_north_higher && is_south_higher && is_west_higher && is_east_higher { + risks += (cave_height as u64) + 1; + } + } + } + + Ok(risks) } fn main() { const INPUT_PATH: &str = "data/input.txt"; @@ -41,8 +44,8 @@ fn main() { Err(err) => { eprintln!("Could not process file {}:\n {}", INPUT_PATH, err); } - Ok(output) => { - println!("output sum: {}", output); + Ok(risks) => { + println!("total risk: {}", risks); } }, Err(err) => { diff --git a/src/matrix.rs b/src/matrix.rs new file mode 100644 index 0000000..eafa205 --- /dev/null +++ b/src/matrix.rs @@ -0,0 +1,53 @@ +use std::error; +use std::fmt; +use std::ops; + +#[derive(Debug)] +pub struct InvalidMatrix {} + +impl fmt::Display for InvalidMatrix { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Matrix is invalid") + } +} + +impl error::Error for InvalidMatrix {} + +pub struct Matrix { + raw: Vec, + width: usize, +} + +impl ops::Index<(usize, usize)> for Matrix { + type Output = u8; + + fn index(&self, index: (usize, usize)) -> &Self::Output { + self.get(index) + .unwrap_or_else(|| panic!("matrix index {:#?} out of bounds", index)) + } +} + +impl Matrix { + pub fn try_from_raw(raw: &[u8], width: usize) -> Result { + if 0 != raw.len() % width { + return Err(InvalidMatrix {}); + } + + Ok(Matrix { + raw: Vec::from(raw), + width, + }) + } + + pub fn get_height(&self) -> usize { + if 0 == self.width { + 0 + } else { + self.raw.len() / self.width + } + } + + pub fn get(&self, index: (usize, usize)) -> Option<&u8> { + self.raw.get(index.0 + index.1 * self.width) + } +} diff --git a/src/solver.rs b/src/solver.rs deleted file mode 100644 index da51ff3..0000000 --- a/src/solver.rs +++ /dev/null @@ -1,79 +0,0 @@ -use crate::digit::Digit; - -use std::collections::HashMap; - -use std::fmt; - -#[derive(Debug)] -pub struct InvalidKeyInput(String); - -impl fmt::Display for InvalidKeyInput { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "invalid key input string.\n {}", self.0) - } -} - -impl std::error::Error for InvalidKeyInput {} - -pub struct Key { - four: Digit, - seven: Digit, -} - -impl Key { - pub fn try_from_input(input: &[&str]) -> Result { - let mut key_map: HashMap = HashMap::with_capacity(2); - - for digit in input { - match digit.chars().count() { - 3 => { - key_map.insert(7, Digit::from(*digit)); - } - 4 => { - key_map.insert(4, Digit::from(*digit)); - } - _ => {} - } - } - - for expected_digit in [4, 7] { - if !key_map.contains_key(&expected_digit) { - return Err(InvalidKeyInput(format!("missing digit {}", expected_digit))); - } - } - - Ok(Key { - four: key_map.remove(&4).unwrap(), - seven: key_map.remove(&7).unwrap(), - }) - } - - pub fn solve(&self, s: &str) -> Option { - let digit = Digit::from(s); - match s.chars().count() { - 2 => Some(1), - 3 => Some(7), - 4 => Some(4), - 5 => { - if digit.contains(&self.seven) { - Some(3) - } else if 3 == digit.diff(&self.four).chars().count() { - Some(2) - } else { - Some(5) - } - } - 6 => { - if digit.contains(&self.four) { - Some(9) - } else if digit.contains(&self.seven) { - Some(0) - } else { - Some(6) - } - } - 7 => Some(8), - _ => None, - } - } -}