1+ use heapless:: Vec as HeaplessVec ;
12advent_of_code:: solution!( 7 ) ;
2- use itertools:: Itertools ;
33
44#[ derive( Debug , Clone , Copy , PartialEq , Eq ) ]
55enum Op {
@@ -8,7 +8,6 @@ enum Op {
88 Concat ,
99}
1010
11- type OpVec = Vec < Op > ;
1211#[ derive( Debug ) ]
1312struct 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+
6694pub 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) ]
86100mod 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