90 lines
2.5 KiB
Rust
90 lines
2.5 KiB
Rust
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::<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 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::<i32>().unwrap();
|
|
let b = b.parse::<i32>().unwrap();
|
|
(a, b)
|
|
})
|
|
.collect::<Vec<(i32, i32)>>()
|
|
}
|
|
|
|
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::<i32>())
|
|
.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);
|
|
}
|
|
}
|