diff --git a/Cargo.lock b/Cargo.lock index 052335b..8a563e2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,3 +5,21 @@ version = 3 [[package]] name = "advent_2023" version = "0.1.0" +dependencies = [ + "itertools", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "itertools" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d47946d458e94a1b7bcabbf6521ea7c037062c81f534615abcad76e84d4970d" +dependencies = [ + "either", +] diff --git a/Cargo.toml b/Cargo.toml index 193abbb..4c2beb0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,3 +6,4 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +itertools = "0.7.4" diff --git a/src/three/mod.rs b/src/three/mod.rs index 1c5ebdb..7b41353 100644 --- a/src/three/mod.rs +++ b/src/three/mod.rs @@ -1,14 +1,54 @@ use std::{str::FromStr, path::Path, option::Option}; +use itertools::Itertools; + use crate::input::{AdventError, read_into_vec}; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq, Eq, Hash)] pub struct Number { value: u32, position: u8, length: u8 } +#[derive(Debug, Clone)] +pub struct Symbol { + position: u8, + symbol: char, +} + +impl From for Symbol { + fn from(value: u8) -> Self { + Symbol{position: value, symbol: ' '} + } +} + +impl PartialEq for Symbol { + fn eq(&self, other: &Self) -> bool { + self.position == other.position + } +} + +impl PartialOrd for Symbol { + fn partial_cmp(&self, other: &Self) -> Option { + match self.position.partial_cmp(&other.position) { + Some(core::cmp::Ordering::Equal) => {} + ord => return ord, + } + self.symbol.partial_cmp(&other.symbol) + } +} + +impl Eq for Symbol { + +} + +impl Ord for Symbol { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + self.position.cmp(&other.position) + } +} + impl FromStr for RowInfo { type Err = AdventError; @@ -25,7 +65,7 @@ impl FromStr for RowInfo { struct RowInfo { partial_start: Option, partial_number: Option, - pub symbol_positions: Vec, + pub symbols: Vec, pub numbers: Vec, } @@ -34,13 +74,13 @@ impl RowInfo { Self { partial_start: None, partial_number: None, - symbol_positions: Vec::::new(), + symbols: Vec::::new(), numbers: Vec::::new() } } - fn add_symbol(&mut self, i: usize) -> Result<(), AdventError> { - self.symbol_positions.push(i as u8); + fn add_symbol(&mut self, b: u8, i: usize) -> Result<(), AdventError> { + self.symbols.push(Symbol {position: i as u8, symbol: b as char}); if self.partial_start != None { self.finish_digit(i)? } @@ -61,7 +101,7 @@ impl RowInfo { fn process(&mut self, i: usize, b: &u8) -> Result<(), AdventError> { if b != &b'.' && !b.is_ascii_digit() { - self.add_symbol(i)? + self.add_symbol(*b, i)? } else if b.is_ascii_digit() { if self.partial_start.is_none() { @@ -92,7 +132,7 @@ impl Default for RowInfo { } } -pub fn gen_coords(y: usize, number: &Number) -> Vec<(u8, u8)> { +pub fn gen_coords_number(y: usize, number: &Number) -> Vec<(u8, u8)> { let mut vec = Vec::<(u8, u8)>::new(); let min_x = if number.position == 0 { 0 @@ -112,17 +152,44 @@ pub fn gen_coords(y: usize, number: &Number) -> Vec<(u8, u8)> { vec } +pub fn gen_coords_symbol(y: usize, symbol: &Symbol) -> Vec<(u8,u8)> { + let mut vec = Vec::<(u8, u8)>::new(); + let min_x = if symbol.position == 0 { + 0 + } else { + symbol.position - 1 + }; + let max_x = symbol.position + 1 + 1; + for x in min_x..max_x { + if y != 0 { + vec.push((x, y as u8 - 1)); + } + if x < symbol.position || x > symbol.position { + vec.push((x, y as u8)); + } + vec.push((x, y as u8 + 1)); + } + vec +} + +fn filter_gears(rows: &mut Vec) -> &mut Vec { + for row in rows.iter_mut() { + row.symbols = row.symbols.clone().into_iter().filter(|x| { x.symbol == '*' }).collect::>() + } + rows +} + pub fn one() -> Result<(), AdventError> { let rows = read_into_vec::(Path::new("resources/input3.txt"))?; let mut sum: u32 = 0; for (i, row) in rows.iter().enumerate() { for number in row.numbers.iter() { - let coords = gen_coords(i, number); + let coords = gen_coords_number(i, number); if coords.iter().any(|c| -> bool { if c.1 as usize >= rows.len() { false } else { - rows[c.1 as usize].symbol_positions.binary_search(&c.0).is_ok() + rows[c.1 as usize].symbols.binary_search(&c.0.into()).is_ok() } }) { sum += number.value; @@ -134,5 +201,35 @@ pub fn one() -> Result<(), AdventError> { } pub fn two() -> Result<(), AdventError> { + let mut rows = read_into_vec::(Path::new("resources/input3.txt"))?; + rows = filter_gears(&mut rows).clone(); + let mut sum: u32 = 0; + for (i, row) in rows.iter().enumerate() { + for symbol in row.symbols.iter() { + let coords = gen_coords_symbol(i, symbol); + let numbers = coords.iter().map(|(x, y)| { + if *y as usize >= rows.len() { + None + } else { + let relevant_numbers = rows[*y as usize].numbers.clone().into_iter().filter(|number| {*x >= number.position && *x < number.position + number.length}).collect::>(); + if relevant_numbers.len() == 1 { + Some(relevant_numbers[0].clone()) + } else { + None + } + } + }) + .filter(|x| {x.is_some()}) + .map(|x| {x.unwrap()}) + .unique() + .collect::>(); + + if numbers.len() == 2 { + sum += numbers[0].value * numbers[1].value; + } + } + } + println!("{}", sum); + Ok(()) } \ No newline at end of file