day three part two

main
Zynh0722 2023-12-03 03:00:37 -08:00
parent 55dcfcd7e8
commit d8bfa2e21b
2 changed files with 112 additions and 4 deletions

View File

@ -7,9 +7,9 @@ edition = "2021"
name = "pone" name = "pone"
path = "src/one.rs" path = "src/one.rs"
# [[bin]] [[bin]]
# name = "ptwo" name = "ptwo"
# path = "src/two.rs" path = "src/two.rs"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

View File

@ -1,8 +1,116 @@
use std::io::{self, Read}; use std::{
collections::HashMap,
io::{self, Read},
};
fn main() { fn main() {
let mut buf = String::new(); let mut buf = String::new();
io::stdin().read_to_string(&mut buf).unwrap(); io::stdin().read_to_string(&mut buf).unwrap();
let lines: Vec<String> = buf.lines().map(ToOwned::to_owned).collect(); let lines: Vec<String> = 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<NumberPos>> = 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::<usize>)
.product::<usize>()
})
.sum();
print!("{total}");
}
type NumberPos = (std::ops::Range<usize>, usize);
fn get_numbers<S>(s: S) -> Vec<(usize, usize)>
where
S: AsRef<str>,
{
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<usize>;
}
impl AsRange for (usize, usize) {
fn as_range(&self) -> std::ops::Range<usize> {
self.0..self.1
}
}
fn is_near_star(
source: &Vec<String>,
number_line: usize,
number_positions: std::ops::Range<usize>,
) -> 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<usize>, max: usize) -> std::ops::Range<usize> {
let end = if input.end > max { max } else { input.end };
input.start..end
}
fn fuzz_range(input: std::ops::Range<usize>) -> std::ops::Range<usize> {
input.start.checked_sub(1).unwrap_or(input.start)..input.end + 1
} }