day three part two
This commit is contained in:
parent
55dcfcd7e8
commit
d8bfa2e21b
2 changed files with 112 additions and 4 deletions
|
@ -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
|
||||||
|
|
||||||
|
|
110
three/src/two.rs
110
three/src/two.rs
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue