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