From d6551853362800a862d0cfb2cf7179f6d8aeb2b5 Mon Sep 17 00:00:00 2001 From: Fabian Schmidt Date: Tue, 3 Dec 2024 10:12:20 +0100 Subject: [PATCH] y2024d3 second try part 2 --- y2024/src/days/d3.rs | 79 ++++++++++++++++++++++++++++++++++---------- 1 file changed, 62 insertions(+), 17 deletions(-) diff --git a/y2024/src/days/d3.rs b/y2024/src/days/d3.rs index fbb6d87..59cc9a0 100644 --- a/y2024/src/days/d3.rs +++ b/y2024/src/days/d3.rs @@ -6,6 +6,10 @@ pub fn process_part1(input: &str) -> i32 { .sum() } +// Could use this regex but wouldn't know how to solve part 2 +// /mul\([0-9]{1,3},[0-9]{1,3}\)/g +// /don't\(\).*do\(\)/g would select anything between don't() and do() +// not sure how to invert this and combine fn extract_mul_pairs(line: &str) -> Vec<(i32, i32)> { let mut pairs = Vec::new(); for (idx, _) in line.match_indices("mul(") { @@ -50,38 +54,71 @@ fn extract_mul_pairs(line: &str) -> Vec<(i32, i32)> { pairs } -fn remove_donts(line: &str) -> String { - let mut new_line = line.to_string(); - - while let Some(dont_func) = new_line.find("don't()") { - let mut range_end = new_line.len(); - while let Some(do_func) = new_line.find("do()") { - if do_func < dont_func { - new_line.replace_range(do_func..do_func + 4, "####"); +fn extract_mul_pairs_dont(line: &str) -> Vec<(i32, i32)> { + let mut pairs = Vec::new(); + for (idx, _) in line.match_indices("mul(") { + if let Some(dont_func) = line[..idx].rfind("don't()") { + if let Some(do_func) = line[..idx].rfind("do()") { + if do_func < dont_func { + continue; + } + } else { continue; } - range_end = do_func + 4; - break; } - let replace_with = "#".repeat(range_end - dont_func); - new_line.replace_range(dont_func..range_end, &replace_with); + let mut invalid = false; + let mut comma_pos = 0; + let mut pair = ("".to_string(), "".to_string()); + // max length of parenthesis == 9 + for paren_idx in 0..9 { + let paren_content = match line.as_bytes().get(idx + 4 + paren_idx) { + Some(content) => *content as char, + None => { + invalid = true; + break; + } + }; + if paren_content == ')' { + if comma_pos == 0 { + invalid = true; + } + break; + } + if paren_content == ',' { + comma_pos = paren_idx; + continue; + } + if !paren_content.is_ascii_digit() { + invalid = true; + break; + } + if comma_pos == 0 { + pair.0.push(paren_content); + } else { + pair.1.push(paren_content); + } + } + if !invalid { + let a = pair.0.parse::().unwrap(); + let b = pair.1.parse::().unwrap(); + pairs.push((a, b)); + } } - new_line + pairs } pub fn process_part2(input: &str) -> i32 { input .lines() - .map(|line| { - let line = remove_donts(line); - extract_mul_pairs(&line) - }) + .map(extract_mul_pairs_dont) .map(|pairs| pairs.iter().map(|(a, b)| a * b).sum::()) .sum() } #[cfg(test)] mod tests { + use std::fs; + use super::*; const INPUT: &str = @@ -96,6 +133,14 @@ mod tests { assert_eq!(result, 161); } + #[test] + fn res1() { + let root = env!("CARGO_MANIFEST_DIR"); + let content = fs::read_to_string(format!("{root}/resources/3_input.txt")).unwrap(); + let result = process_part1(&content); + assert_eq!(result, 183788984); + } + #[test] fn part2() { let result = process_part2(INPUT_2);