Compare commits

...

10 Commits

Author SHA1 Message Date
c665ed878e Use Arc to not clone cached permutations 2025-06-30 10:57:30 -05:00
8825d97858 Improve type names 2025-06-30 10:06:29 -05:00
4250028c6a Remove unused import 2025-06-16 13:51:58 -05:00
16e726db6b Make const "sets" 2025-06-16 13:51:07 -05:00
ec0267a455 Only make a single cache key (minor optimization) 2025-06-16 13:36:02 -05:00
a7b3d9225b Remove commented out code 2025-06-16 13:33:05 -05:00
f235c46bd4 Add caching back in 2025-06-16 13:32:26 -05:00
3815d496b9 Finish day 7 part 2 2025-06-16 13:07:41 -05:00
9f25697af4 Comment out old implementation 2025-06-16 12:59:46 -05:00
e2cb839086 Better permutation creation 2025-06-16 12:58:38 -05:00
3 changed files with 96 additions and 41 deletions

View File

@@ -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;
}
}

View File

@@ -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
}

View File

@@ -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(())
}