From d8bfa2e21b50edae3ec6d0156f21434dc06f7f22 Mon Sep 17 00:00:00 2001 From: Zynh0722 Date: Sun, 3 Dec 2023 03:00:37 -0800 Subject: [PATCH] day three part two --- three/Cargo.toml | 6 +-- three/src/two.rs | 110 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 112 insertions(+), 4 deletions(-) diff --git a/three/Cargo.toml b/three/Cargo.toml index d403595..c5a10ac 100644 --- a/three/Cargo.toml +++ b/three/Cargo.toml @@ -7,9 +7,9 @@ edition = "2021" name = "pone" path = "src/one.rs" -# [[bin]] -# name = "ptwo" -# path = "src/two.rs" +[[bin]] +name = "ptwo" +path = "src/two.rs" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/three/src/two.rs b/three/src/two.rs index b890859..f0242c5 100644 --- a/three/src/two.rs +++ b/three/src/two.rs @@ -1,8 +1,116 @@ -use std::io::{self, Read}; +use std::{ + collections::HashMap, + io::{self, Read}, +}; fn main() { let mut buf = String::new(); io::stdin().read_to_string(&mut buf).unwrap(); let lines: Vec = buf.lines().map(ToOwned::to_owned).collect(); + + let line_number_indecies: Vec<_> = lines.iter().map(get_numbers).collect(); + + // tuple of the line number and character indexes for our list of lines + let numbers = line_number_indecies + .iter() + .enumerate() + .flat_map(|(line, idxs)| { + idxs.iter() + .map(AsRange::as_range) + .zip(std::iter::repeat(line)) + }); + + let mut star_counter: HashMap<(usize, usize), Vec> = HashMap::new(); + for (positions, line) in numbers.clone() { + if let Some((star_line, star_pos, number)) = is_near_star(&lines, line, positions.clone()) { + star_counter + .entry((star_line, star_pos)) + .and_modify(|numbers| numbers.push(number.clone())) + .or_insert(Vec::from([number])); + } + } + + let total: usize = star_counter + .values_mut() + .filter(|numbers| numbers.len() == 2) + .map(|numbers| { + numbers + .iter() + .map(|(positions, line)| &lines[*line][positions.clone()]) + .flat_map(str::parse::) + .product::() + }) + .sum(); + + print!("{total}"); +} + +type NumberPos = (std::ops::Range, usize); + +fn get_numbers(s: S) -> Vec<(usize, usize)> +where + S: AsRef, +{ + let s = s.as_ref(); + + let mut number_indecies = Vec::new(); + + let mut idx = 0; + while idx < s.len() { + if s.chars().nth(idx).unwrap().is_ascii_digit() { + let start_index = idx; + while idx < s.len() && s.chars().nth(idx).unwrap().is_ascii_digit() { + idx += 1; + } + let end_index = idx; + + number_indecies.push((start_index, end_index)); + } else { + idx += 1; + } + } + + number_indecies +} + +trait AsRange { + fn as_range(&self) -> std::ops::Range; +} + +impl AsRange for (usize, usize) { + fn as_range(&self) -> std::ops::Range { + self.0..self.1 + } +} + +fn is_near_star( + source: &Vec, + number_line: usize, + number_positions: std::ops::Range, +) -> Option<(usize, usize, NumberPos)> { + let mut star = None; + 'outer: for line in clamp_range(fuzz_range(number_line..number_line + 1), source.len()) { + for position in clamp_range(fuzz_range(number_positions.clone()), source[line].len()) { + match source[line].chars().nth(position).unwrap() { + '*' => { + star = Some((position, line, (number_positions, number_line))); + break 'outer; + } + _ => (), + } + } + } + + star +} + +fn clamp_range(input: std::ops::Range, max: usize) -> std::ops::Range { + let end = if input.end > max { max } else { input.end }; + + input.start..end +} + +fn fuzz_range(input: std::ops::Range) -> std::ops::Range { + input.start.checked_sub(1).unwrap_or(input.start)..input.end + 1 }