use regex::Regex; pub fn process_part1(input: &str) -> i32 { input .lines() .map(extract_mul_pairs) .map(|pairs| pairs.iter().map(|(a, b)| a * b).sum::()) .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 first don't() and last do() // not sure how to fix, invert and combine this fn extract_mul_pairs(line: &str) -> Vec<(i32, i32)> { let reg = Regex::new(r"mul\([0-9]{1,3},[0-9]{1,3}\)").unwrap(); reg.find_iter(line) .map(|m| { let match_str = m.as_str(); let (a, b) = match_str[4..match_str.len() - 1].split_once(",").unwrap(); let a = a.parse::().unwrap(); let b = b.parse::().unwrap(); (a, b) }) .collect::>() } fn remove_donts(line: &str) -> String { let mut new_line = line.to_string(); loop { println!("len {}", line.len()); let mut end_range = new_line.len() - 1; if let Some(dont_idx) = new_line.find("don't()") { if let Some(do_idx) = new_line.find("do()") { if dont_idx < do_idx { end_range = do_idx + 4; } } println!("dont {dont_idx} to {end_range}"); new_line.replace_range(dont_idx..end_range, ""); } else { return new_line; } } } pub fn process_part2(input: &str) -> i32 { input .lines() .map(|line| { let line = remove_donts(line); extract_mul_pairs(&line) }) .map(|pairs| pairs.iter().map(|(a, b)| a * b).sum::()) .sum() } #[cfg(test)] mod tests { use std::fs; use super::*; const INPUT: &str = "xmul(2,4)%&mul[3,7]!@^do_not_mul(5,5)+mul(32,64]then(mul(11,8)mul(8,5))mul( 1, 3)"; const INPUT_2: &str = "xmul(2,4)&mul[3,7]!^don't()_mul(5,5)+mul(32,64](mul(11,8)undo()?mul(8,5))"; #[test] fn part1() { let result = process_part1(INPUT); 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); assert_eq!(result, 48); } }