Complete 2023 Day 3 Part 1

This commit is contained in:
Timothy Warren 2023-12-07 13:31:14 -05:00
parent da5f674811
commit 979d241bb8

View File

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