106 lines
2.4 KiB
Rust
Raw Normal View History

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<u64>)> {
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<u64>,
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<u64>)>,
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>)>) -> 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>)>) -> 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<String> = 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));
}
}