Skip to content

Commit 2fe47f6

Browse files
committed
Day 7
1 parent 1b38af8 commit 2fe47f6

File tree

1 file changed

+57
-55
lines changed

1 file changed

+57
-55
lines changed

src/bin/07.rs

Lines changed: 57 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1+
use heapless::Vec as HeaplessVec;
12
advent_of_code::solution!(7);
2-
use itertools::Itertools;
33

44
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55
enum Op {
@@ -8,7 +8,6 @@ enum Op {
88
Concat,
99
}
1010

11-
type OpVec = Vec<Op>;
1211
#[derive(Debug)]
1312
struct EquationData {
1413
test_value: u64,
@@ -23,81 +22,84 @@ impl EquationData {
2322
Self { test_value, values }
2423
}
2524

26-
fn eval(&self, ops: &OpVec) -> u64 {
27-
let mut res = 0;
28-
let mut op = Op::Add;
29-
for i in 0..self.values.len() {
30-
let v = self.values[i];
31-
res = match op {
32-
Op::Add => res + v,
33-
Op::Mul => res * v,
34-
Op::Concat => {
35-
let char_count = v.to_string().len() as u32;
36-
res * 10_u64.pow(char_count) + v
25+
#[inline]
26+
fn has_valid_ops_combination(&self, available_ops: &[Op]) -> bool {
27+
let needed_ops = self.values.len() - 1;
28+
if needed_ops == 0 {
29+
return self.values[0] == self.test_value;
30+
}
31+
32+
const OPS_SIZE: usize = 16;
33+
const STACK_SIZE: usize = 32;
34+
35+
let mut stack = HeaplessVec::<_, STACK_SIZE>::new();
36+
stack
37+
.push((self.values[0], HeaplessVec::<_, OPS_SIZE>::new()))
38+
.unwrap();
39+
40+
while let Some((current_value, mut ops)) = stack.pop() {
41+
if ops.len() == needed_ops {
42+
if current_value == self.test_value {
43+
return true;
3744
}
38-
};
39-
if i < ops.len() {
40-
op = ops[i];
45+
continue;
46+
}
47+
48+
let next_idx = ops.len() + 1;
49+
let next_value = self.values[next_idx];
50+
51+
// Try each available operation
52+
for &op in available_ops {
53+
let new_value = match op {
54+
Op::Add => current_value + next_value,
55+
Op::Mul => current_value * next_value,
56+
Op::Concat => {
57+
let char_count = next_value.to_string().len() as u32;
58+
current_value * 10_u64.pow(char_count) + next_value
59+
}
60+
};
61+
62+
// Skip if we've already exceeded the target
63+
if new_value > self.test_value {
64+
continue;
65+
}
66+
67+
// Create new ops vector and push to stack
68+
ops.push(op).unwrap();
69+
stack.push((new_value, ops.clone())).unwrap();
70+
ops.pop();
4171
}
4272
}
43-
res
73+
74+
false
4475
}
4576
}
4677

47-
pub fn part_one(input: &str) -> Option<u64> {
48-
const ALL_OPS: [Op; 2] = [Op::Add, Op::Mul];
78+
fn solve(input: &str, ops: &[Op]) -> Option<u64> {
4979
let sum = input
5080
.lines()
5181
.filter(|l| !l.is_empty())
52-
.map(|l| EquationData::parse(l))
53-
.filter(|eq| {
54-
for ops in std::iter::repeat_n(ALL_OPS, eq.values.len() - 1).multi_cartesian_product() {
55-
if eq.eval(&ops) == eq.test_value {
56-
return true;
57-
}
58-
}
59-
false
60-
})
82+
.map(EquationData::parse)
83+
.filter(|eq| eq.has_valid_ops_combination(ops))
6184
.map(|eq| eq.test_value)
6285
.sum();
6386
Some(sum)
6487
}
6588

89+
pub fn part_one(input: &str) -> Option<u64> {
90+
const ALL_OPS: [Op; 2] = [Op::Add, Op::Mul];
91+
solve(input, &ALL_OPS)
92+
}
93+
6694
pub fn part_two(input: &str) -> Option<u64> {
6795
const ALL_OPS: [Op; 3] = [Op::Add, Op::Mul, Op::Concat];
68-
let sum = input
69-
.lines()
70-
.filter(|l| !l.is_empty())
71-
.map(|l| EquationData::parse(l))
72-
.filter(|eq| {
73-
for ops in std::iter::repeat_n(ALL_OPS, eq.values.len() - 1).multi_cartesian_product() {
74-
if eq.eval(&ops) == eq.test_value {
75-
return true;
76-
}
77-
}
78-
false
79-
})
80-
.map(|eq| eq.test_value)
81-
.sum();
82-
Some(sum)
96+
solve(input, &ALL_OPS)
8397
}
8498

8599
#[cfg(test)]
86100
mod tests {
87101
use super::*;
88102

89-
#[test]
90-
fn test_eval() {
91-
let eq = EquationData {
92-
test_value: 10,
93-
values: vec![1, 2, 3],
94-
};
95-
assert_eq!(eq.eval(&vec![Op::Add, Op::Add]), 6);
96-
assert_eq!(eq.eval(&vec![Op::Add, Op::Mul]), 9);
97-
assert_eq!(eq.eval(&vec![Op::Mul, Op::Add]), 5);
98-
assert_eq!(eq.eval(&vec![Op::Mul, Op::Mul]), 6);
99-
}
100-
101103
#[test]
102104
fn test_part_one() {
103105
let result = part_one(&advent_of_code::template::read_file("examples", DAY));

0 commit comments

Comments
 (0)