use std::{env, fs}; fn read_input(path: &str) -> String { fs::read_to_string(path).expect("Cannot read file.") } fn add(a: u64, b: u64) -> u64 { a + b } fn mul(a: u64, b: u64) -> u64 { a * b } fn concat(a: u64, b: u64) -> u64 { format!("{a}{b}").parse().unwrap() } fn parse_input(input: &str) -> Vec<(u64, Vec)> { input .lines() .filter(|line| !line.is_empty()) .map(|line| { let split_line = line.split_once(": ").unwrap(); ( split_line.0.parse().unwrap(), split_line .1 .split_whitespace() .map(|s| s.parse().unwrap()) .rev() .collect(), ) }) .collect() } fn is_valid( data: &mut Vec, acc: u64, target: u64, operators: &Vec<&fn(u64, u64) -> u64>, ) -> bool { if data.is_empty() { return target == acc; } if acc > target { return false; } let old = data.pop().unwrap(); for operator in operators { if is_valid(data, operator(acc, old), target, operators) { return true; } } data.push(old); false } fn sum_valid( calibration_data: &Vec<(u64, Vec)>, operators: &Vec<&fn(u64, u64) -> u64>, ) -> u64 { let mut sum_valid = 0; let calibration_data = calibration_data.clone(); for calibration in calibration_data { let mut x = calibration.1; let acc = x.pop().unwrap(); if is_valid(&mut x, acc, calibration.0, operators) { sum_valid += calibration.0; } } sum_valid } fn part_1(input: &Vec<(u64, Vec)>) -> u64 { let valid_operators = vec![&(add as fn(u64, u64) -> u64), &(mul as fn(u64, u64) -> u64)]; sum_valid(input, &valid_operators) } fn part_2(input: &Vec<(u64, Vec)>) -> u64 { let valid_operators = vec![ &(add as fn(u64, u64) -> u64), &(mul as fn(u64, u64) -> u64), &(concat as fn(u64, u64) -> u64), ]; sum_valid(input, &valid_operators) } fn main() { let args: Vec = env::args().collect(); for arg in args.iter().skip(1) { let input = read_input(&arg); let calibration_data = parse_input(&input); println!("[{}]", &arg); println!("\t[Part 1] => Answer is '{}'.", part_1(&calibration_data)); println!("\t[Part 2] => Answer is '{}'.", part_2(&calibration_data)); } }