diff --git a/2023/day3/src/main.rs b/2023/day3/src/main.rs index 74879ba..c544a84 100644 --- a/2023/day3/src/main.rs +++ b/2023/day3/src/main.rs @@ -3,7 +3,7 @@ use std::ops::Range; const FILE_STR: &'static str = include_str!("input.txt"); -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, Eq, PartialEq)] struct NumberLocation { start: usize, end: usize, @@ -33,7 +33,6 @@ impl NumberLocation { enum ValueType { Number(usize), Symbol(char), - Err(char), Empty, } @@ -49,35 +48,37 @@ impl Grid { use ValueType::*; let len = input_str.split('\n').next().unwrap().len(); - let chars: Vec = input_str.replace("\n", "").chars().collect(); let mut values: Vec = Vec::new(); let mut numbers: Vec = Vec::new(); - let mut prev = Empty; - let symbols = vec!['%', '&', '/', '*', '=', '+', '#', '@', '-', '$']; + input_str + .split('\n') + .map(|row| row.chars()) + .enumerate() + .for_each(|(r, char_row)| { + let mut prev = Empty; + char_row.enumerate().for_each(|(c, ch)| { + let n = len * r + c; + if ch.is_digit(10) { + if let Number(_) = prev { + let final_num = { numbers.len() - 1 }; + numbers.get_mut(final_num).unwrap().add_digit(ch); + } else { + let nl = NumberLocation::new(n, ch); + numbers.push(nl); + } - chars.iter().enumerate().for_each(|(i, ch)| { - if ch.is_digit(10) { - if let Number(_) = prev { - let final_num = { numbers.len() - 1 }; - numbers.get_mut(final_num).unwrap().add_digit(*ch); - } else { - let nl = NumberLocation::new(i, *ch); - numbers.push(nl); - } + prev = Number(numbers.len() - 1); + } else if ch == '.' { + prev = Empty; + } else { + prev = Symbol(ch); + } - prev = Number(numbers.len() - 1); - } else if *ch == '.' { - prev = Empty; - } else if symbols.contains(ch) { - prev = Symbol(*ch); - } else { - prev = Err(*ch); - } - - values.push(prev); - }); + values.push(prev); + }); + }); Grid { line_size: len, @@ -104,57 +105,60 @@ impl Grid { (idx % self.num_cols(), idx / self.num_cols()) } - fn adjacent_ind(&self, i: usize) -> HashSet { + fn adjacent_ind(&self, r: Range) -> HashSet { + let min = r.start; + let max = r.end - 1; let mut ind = HashSet::new(); - if i >= self.values.len() { + if max >= self.values.len() { return ind; } - let (col, row) = self.idx_xy(i); + let (min_col, row) = self.idx_xy(min); + let (max_col, erow) = self.idx_xy(max); + assert_eq!(row, erow, "All the digits should be in the same row"); // Forwards/backwards - if col > 0 { - ind.insert(self.xy_idx(col - 1, row)); + if min_col > 0 { + ind.insert(self.xy_idx(min_col - 1, row)); } - if col + 1 < self.num_cols() { - ind.insert(self.xy_idx(col + 1, row)); + if max_col + 1 < self.num_cols() { + ind.insert(self.xy_idx(max_col + 1, row)); } // Row above/below - if row + 1 < self.num_rows() { - ind.insert(self.xy_idx(col, row + 1)); - } - if row > 0 { - ind.insert(self.xy_idx(col, row - 1)); + for x in r { + let (col, row) = self.idx_xy(x); + + if row + 1 < self.num_rows() { + ind.insert(self.xy_idx(col, row + 1)); + } + if row > 0 { + ind.insert(self.xy_idx(col, row - 1)); + } } - // Diagonals (x+1, y-1),(x-1, y-1),(x+1, y+1),(x-1,y+1) - if col > 0 && row > 0 { - ind.insert(self.xy_idx(col - 1, row - 1)); + // Diagonals (min-1, y-1),(min-1,y+1),(max+1, y-1),(max+1, y+1) + if min_col > 0 && row > 0 { + ind.insert(self.xy_idx(min_col - 1, row - 1)); } - if col > 0 && row + 1 < self.num_rows() { - ind.insert(self.xy_idx(col - 1, row + 1)); + if min_col > 0 && row + 1 < self.num_rows() { + ind.insert(self.xy_idx(min_col - 1, row + 1)); } - if col + 1 < self.num_cols() && row > 0 { - ind.insert(self.xy_idx(col + 1, row - 1)); + if max_col + 1 < self.num_cols() && row > 0 { + ind.insert(self.xy_idx(max_col + 1, row - 1)); } - if col + 1 < self.num_cols() && row + 1 < self.num_rows() { - ind.insert(self.xy_idx(col + 1, row + 1)); + if max_col + 1 < self.num_cols() && row + 1 < self.num_rows() { + ind.insert(self.xy_idx(max_col + 1, row + 1)); } ind } fn find_adjacent(&self, r: Range) -> Vec { - let mut adj = Vec::new(); - - for i in r { - self.adjacent_ind(i) - .into_iter() - .for_each(|ind| adj.push(self.values[ind])); - } - - adj + self.adjacent_ind(r) + .into_iter() + .map(|ind| self.values[ind]) + .collect() } fn is_part_number(&self, r: Range) -> bool { @@ -181,7 +185,7 @@ impl Grid { } fn get_part_number_sum(&self) -> usize { - self.get_unique_part_numbers().iter().sum() + self.get_part_numbers().iter().sum() } } @@ -201,33 +205,30 @@ fn main() { mod tests { const EXAMPLE_FILE_STR: &'static str = include_str!("example_input.txt"); use super::*; - use std::iter::FromIterator; + use FromIterator; use ValueType::*; #[test] fn test_get_part_number_sum_part_1() { let grid = Grid::parse(FILE_STR); - assert!(grid.get_part_number_sum() < 1645975); + assert_eq!(grid.get_part_number_sum(), 525181); } #[test] fn test_adjacent_index() { let grid = Grid::parse(EXAMPLE_FILE_STR); - assert_eq!(grid.adjacent_ind(5), HashSet::from([4, 6, 14, 15, 16])); - } - - #[test] - fn test_find_adjacent() { - let grid = Grid::parse(EXAMPLE_FILE_STR); - let adjacent = grid.find_adjacent(5..6); - let hadj = HashSet::from_iter(adjacent.iter().cloned()); - assert_eq!(hadj, HashSet::from([Empty, Number(1)])); + let actual = grid.adjacent_ind(62..65); + assert_eq!(12, actual.len()); + assert_eq!( + HashSet::from_iter(actual.iter().cloned()), + HashSet::from([51, 52, 53, 54, 55, 61, 65, 71, 72, 73, 74, 75]) + ); } #[test] fn test_get_part_numbers() { let grid = Grid::parse(EXAMPLE_FILE_STR); - let expected = [467, 35, 633, 617, 592, 755, 664, 598]; + let expected = [467usize, 35, 633, 617, 592, 755, 664, 598]; assert_eq!(grid.get_part_numbers(), expected); }