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
1 changed files with 69 additions and 68 deletions

View File

@ -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<char> = input_str.replace("\n", "").chars().collect();
let mut values: Vec<ValueType> = Vec::new();
let mut numbers: Vec<NumberLocation> = 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<usize> {
fn adjacent_ind(&self, r: Range<usize>) -> HashSet<usize> {
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<usize>) -> Vec<ValueType> {
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<usize>) -> 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);
}