Compare commits
10 Commits
72492db6ea
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| c665ed878e | |||
| 8825d97858 | |||
| 4250028c6a | |||
| 16e726db6b | |||
| ec0267a455 | |||
| a7b3d9225b | |||
| f235c46bd4 | |||
| 3815d496b9 | |||
| 9f25697af4 | |||
| e2cb839086 |
@@ -1,6 +1,8 @@
|
||||
mod operator_set;
|
||||
|
||||
use operator_set::{Op, create_operator_set};
|
||||
use std::ops::Deref;
|
||||
|
||||
use operator_set::{Op, create_permutations};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Equation {
|
||||
@@ -46,10 +48,6 @@ impl Equation {
|
||||
self.answer
|
||||
}
|
||||
|
||||
pub fn components(&self) -> &Vec<i64> {
|
||||
&self.components
|
||||
}
|
||||
|
||||
fn compute_answer(&self, operators: &[Op]) -> i64 {
|
||||
let mut accumulator = self.components[0];
|
||||
|
||||
@@ -57,17 +55,39 @@ impl Equation {
|
||||
match op {
|
||||
Op::Multiply => accumulator *= self.components[i + 1],
|
||||
Op::Add => accumulator += self.components[i + 1],
|
||||
Op::Concat => {
|
||||
let accumulator_string = format!("{}", accumulator);
|
||||
let component_string = format!("{}", self.components[i + 1]);
|
||||
accumulator = (accumulator_string + &component_string).parse().unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
accumulator
|
||||
}
|
||||
|
||||
pub fn solvable(&self) -> bool {
|
||||
let op_combinations = create_operator_set(self.components.len() - 1);
|
||||
const MULTIPLY_ADD_SET: [Op; 2] = [Op::Add, Op::Multiply];
|
||||
pub fn solvable_multiply_add(&self) -> bool {
|
||||
let op_combinations =
|
||||
create_permutations(&Equation::MULTIPLY_ADD_SET, self.components.len() - 1);
|
||||
|
||||
for combination in op_combinations {
|
||||
if self.answer == self.compute_answer(&combination) {
|
||||
for combination in op_combinations.deref() {
|
||||
if self.answer == self.compute_answer(combination) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
const MULTIPLY_ADD_CONCAT_SET: [Op; 3] = [Op::Add, Op::Multiply, Op::Concat];
|
||||
pub fn solvable_multiply_add_concat(&self) -> bool {
|
||||
let op_combinations = create_permutations(
|
||||
&Equation::MULTIPLY_ADD_CONCAT_SET,
|
||||
self.components.len() - 1,
|
||||
);
|
||||
|
||||
for combination in op_combinations.deref() {
|
||||
if self.answer == self.compute_answer(combination) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,59 +1,79 @@
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
use std::sync::{LazyLock, Mutex};
|
||||
use std::sync::{Arc, LazyLock, Mutex};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
|
||||
pub enum Op {
|
||||
Multiply,
|
||||
Add,
|
||||
Concat,
|
||||
}
|
||||
|
||||
type OperatorCache = HashMap<usize, HashSet<Vec<Op>>>;
|
||||
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
|
||||
struct PermutationCacheKey {
|
||||
size: usize,
|
||||
set: Vec<Op>,
|
||||
}
|
||||
|
||||
impl PermutationCacheKey {
|
||||
fn new(size: usize, set: Vec<Op>) -> PermutationCacheKey {
|
||||
PermutationCacheKey { size, set }
|
||||
}
|
||||
}
|
||||
|
||||
type Permutation = Vec<Op>;
|
||||
type OperatorCache = HashMap<PermutationCacheKey, Arc<HashSet<Permutation>>>;
|
||||
|
||||
static OPERATOR_SET_CACHE: LazyLock<Mutex<OperatorCache>> =
|
||||
LazyLock::new(|| Mutex::new(HashMap::new()));
|
||||
|
||||
fn check_operator_set_cache(cache_key: usize) -> Option<HashSet<Vec<Op>>> {
|
||||
OPERATOR_SET_CACHE.lock().unwrap().get(&cache_key).cloned()
|
||||
fn check_operator_set_cache(cache_key: &PermutationCacheKey) -> Option<Arc<HashSet<Permutation>>> {
|
||||
let lock = OPERATOR_SET_CACHE.lock().unwrap();
|
||||
let cache_value = lock.get(cache_key);
|
||||
cache_value.cloned()
|
||||
}
|
||||
|
||||
fn store_operator_set_in_cache(cache_key: usize, cache_value: HashSet<Vec<Op>>) {
|
||||
fn store_operator_set_in_cache(
|
||||
cache_key: PermutationCacheKey,
|
||||
cache_value: Arc<HashSet<Permutation>>,
|
||||
) {
|
||||
OPERATOR_SET_CACHE
|
||||
.lock()
|
||||
.unwrap()
|
||||
.insert(cache_key, cache_value);
|
||||
}
|
||||
|
||||
fn create_operator_set_recurse(
|
||||
operators_permutation_set: &mut HashSet<Vec<Op>>,
|
||||
operators: Vec<Op>,
|
||||
fn create_permutations_recurse(
|
||||
values: &[Op],
|
||||
len: usize,
|
||||
permutations: &mut HashSet<Permutation>,
|
||||
curr_permutation: Permutation,
|
||||
) {
|
||||
operators_permutation_set.insert(operators.clone());
|
||||
if !operators.contains(&Op::Add) {
|
||||
if curr_permutation.len() == len {
|
||||
permutations.insert(curr_permutation);
|
||||
return;
|
||||
}
|
||||
|
||||
for i in 0..operators.len() {
|
||||
if operators[i] == Op::Multiply {
|
||||
break;
|
||||
}
|
||||
let mut new_operators = operators.clone();
|
||||
new_operators[i] = Op::Multiply;
|
||||
create_operator_set_recurse(operators_permutation_set, new_operators);
|
||||
for v in values {
|
||||
let mut next_permutation = curr_permutation.clone();
|
||||
next_permutation.push(*v);
|
||||
create_permutations_recurse(values, len, permutations, next_permutation);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_operator_set(num_of_operators: usize) -> HashSet<Vec<Op>> {
|
||||
pub fn create_permutations(set: &[Op], len: usize) -> Arc<HashSet<Permutation>> {
|
||||
// Check cache
|
||||
if let Some(cached_value) = check_operator_set_cache(num_of_operators) {
|
||||
return cached_value.clone();
|
||||
let cache_key = PermutationCacheKey::new(len, set.to_vec());
|
||||
if let Some(cached_value) = check_operator_set_cache(&cache_key) {
|
||||
return cached_value;
|
||||
}
|
||||
|
||||
let mut operator_sets: HashSet<Vec<Op>> = HashSet::new();
|
||||
create_operator_set_recurse(&mut operator_sets, vec![Op::Add; num_of_operators]);
|
||||
// Create permutations
|
||||
let mut permutations = HashSet::new();
|
||||
create_permutations_recurse(set, len, &mut permutations, vec![]);
|
||||
|
||||
// Store value in cache
|
||||
store_operator_set_in_cache(num_of_operators, operator_sets.clone());
|
||||
|
||||
operator_sets
|
||||
// Cache and return
|
||||
let permutations = Arc::new(permutations);
|
||||
store_operator_set_in_cache(cache_key, permutations.clone());
|
||||
permutations
|
||||
}
|
||||
|
||||
@@ -33,19 +33,34 @@ fn main() -> Result<(), Box<dyn Error>> {
|
||||
equations.push(Equation::new(&line)?)
|
||||
}
|
||||
|
||||
let mut value_sum = 0;
|
||||
let mut result_add_multiply = 0;
|
||||
let mut result_add_multiply_concat = 0;
|
||||
|
||||
println!("Is solvable?");
|
||||
println!("------------");
|
||||
for equation in equations {
|
||||
let solvable = equation.solvable();
|
||||
println!("{:?} => {}", equation, solvable);
|
||||
if solvable {
|
||||
value_sum += equation.answer();
|
||||
let solvable_add_multiply = equation.solvable_multiply_add();
|
||||
let solvable_add_multiply_concat = equation.solvable_multiply_add_concat();
|
||||
println!(
|
||||
"{:?} => {} | {}",
|
||||
equation, solvable_add_multiply, solvable_add_multiply_concat
|
||||
);
|
||||
if solvable_add_multiply {
|
||||
result_add_multiply += equation.answer();
|
||||
}
|
||||
if solvable_add_multiply_concat {
|
||||
result_add_multiply_concat += equation.answer();
|
||||
}
|
||||
}
|
||||
|
||||
println!("\n Total Calibration Result: {}", value_sum);
|
||||
println!(
|
||||
"\n Total Calibration Result (ADD|MULTIPLY): {}",
|
||||
result_add_multiply
|
||||
);
|
||||
println!(
|
||||
"\n Total Calibration Result (ADD|MULTIPLY|CONCAT): {}",
|
||||
result_add_multiply_concat
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user