fix(day3): Vec of Vec optimization

main
flavien 2023-12-04 09:29:32 +01:00
parent def7d4cf3f
commit f09b4154f2
No known key found for this signature in database
1 changed files with 41 additions and 36 deletions

View File

@ -1,3 +1,4 @@
use std::cmp::min;
use std::fmt::Debug;
use adventofcode2023::utils::get_puzzle;
@ -6,17 +7,18 @@ use adventofcode2023::utils::get_puzzle;
struct PartNumber {
number: u32,
range: std::ops::Range<usize>,
line_index: usize,
valid: bool,
}
type PartsLine = Vec<PartNumber>;
trait SymbolCheckable {
fn is_symbol(&self) -> bool;
}
impl SymbolCheckable for char {
fn is_symbol(&self) -> bool {
*self != '.' && !self.is_ascii_punctuation()
*self != '.' && !self.is_alphanumeric()
}
}
@ -29,62 +31,65 @@ fn parse_number(line: &str) -> (u32, usize) {
(number, number_str.len())
}
fn parse_parts(puzzle: &str) -> Vec<PartNumber> {
let mut part_numbers = Vec::new();
for (line_index, line) in puzzle.lines().enumerate() {
let mut i = 0;
while i < line.len() {
let c = line.chars().nth(i).unwrap();
if c.is_ascii_digit() {
let (number, number_len) = parse_number(&line[i..]);
let part_number = PartNumber {
number,
range: i.saturating_sub(1)..i + number_len + 1,
line_index,
valid: false,
};
i = part_number.range.end;
part_numbers.push(part_number);
} else {
i += 1;
fn parse_parts(puzzle: &str) -> Vec<PartsLine> {
puzzle
.lines()
.map(|line| {
let mut part_numbers = Vec::new();
let mut i = 0;
while i < line.len() {
let c = line.chars().nth(i).unwrap();
if c.is_ascii_digit() {
let (number, number_len) = parse_number(&line[i..]);
let part_number = PartNumber {
number,
range: i.saturating_sub(1)..i + number_len + 1,
valid: false,
};
i = part_number.range.end;
part_numbers.push(part_number);
} else {
i += 1;
}
}
}
}
part_numbers
part_numbers
})
.collect::<Vec<PartsLine>>()
}
fn compute_part_numbers_sum(puzzle: &str) -> u32 {
let mut part_numbers = parse_parts(puzzle);
let mut part_lines = parse_parts(puzzle);
let line_range_max = part_lines.len() - 1;
for (line_index, line) in puzzle.lines().enumerate() {
for (i, c) in line.chars().enumerate() {
if c.is_symbol() {
let line_range = line_index.saturating_sub(1)..=line_index + 1;
part_numbers
let line_range = line_index.saturating_sub(1)..=min(line_index + 1, line_range_max);
part_lines[line_range]
.iter_mut()
.filter(|part_number| {
!part_number.valid && line_range.contains(&part_number.line_index)
})
.filter(|part_number| part_number.range.contains(&i))
.for_each(|part_number: &mut PartNumber| part_number.valid = true);
.flat_map(|v| v.iter_mut())
.filter(|part_number| !part_number.valid)
.for_each(|part_number| part_number.valid = part_number.range.contains(&i));
}
}
}
part_numbers
part_lines
.iter()
.flat_map(|v| v.iter())
.filter(|part_number| part_number.valid)
.fold(0, |acc, part_number| acc + part_number.number)
}
fn compute_gear_ratios_sum(puzzle: &str) -> u32 {
let part_numbers = parse_parts(puzzle);
let part_lines = parse_parts(puzzle);
let line_range_max = part_lines.len() - 1;
let mut gear_ratios_sum = 0;
for (line_index, line) in puzzle.lines().enumerate() {
for (i, c) in line.chars().enumerate() {
if c == '*' {
let line_range = line_index.saturating_sub(1)..=line_index + 1;
let gear_parts = part_numbers
let line_range = line_index.saturating_sub(1)..=min(line_index + 1, line_range_max);
let gear_parts = part_lines[line_range]
.iter()
.filter(|part_number| line_range.contains(&part_number.line_index))
.flat_map(|v| v.iter())
.filter_map(|part_number| match part_number.range.contains(&i) {
true => Some(part_number.number),
false => None,