@@ -17,6 +17,7 @@ fn get_input(filename: &str) -> Vec<String> {
17
17
enum Operation {
18
18
Add ,
19
19
Mul ,
20
+ Cat ,
20
21
}
21
22
22
23
struct Equation {
@@ -29,8 +30,11 @@ fn read_equations(lines: &[String]) -> Vec<Equation> {
29
30
for line in lines {
30
31
let ( lhs, rhs) = line. split_once ( ": " ) . unwrap ( ) ;
31
32
let result = lhs. parse :: < usize > ( ) . unwrap ( ) ;
32
- let operands = rhs. split_ascii_whitespace ( ) . map ( |o| o. parse :: < usize > ( ) . unwrap ( ) ) . collect :: < Vec < _ > > ( ) ;
33
- let eq = Equation { result, operands} ;
33
+ let operands = rhs
34
+ . split_ascii_whitespace ( )
35
+ . map ( |o| o. parse :: < usize > ( ) . unwrap ( ) )
36
+ . collect :: < Vec < _ > > ( ) ;
37
+ let eq = Equation { result, operands } ;
34
38
equations. push ( eq) ;
35
39
}
36
40
@@ -42,19 +46,30 @@ fn read_equations(lines: &[String]) -> Vec<Equation> {
42
46
// operands - the immutable list of operands
43
47
// operation_index - where we currently are working
44
48
// operation - the add/mul we should apply
45
- fn try_operation ( target : usize , result : usize , operands : & Vec < usize > , operation_index : usize , operation : Operation ) -> bool {
46
- if result > target {
49
+ fn try_operation (
50
+ target : usize ,
51
+ result : usize ,
52
+ operands : & Vec < usize > ,
53
+ operation_index : usize ,
54
+ operation : Operation ,
55
+ cat_supported : bool ,
56
+ ) -> bool {
57
+ if result > target || ( !cat_supported && operation == Operation :: Cat ) {
47
58
return false ;
48
59
}
49
60
50
61
// Perform the operation
51
62
let new_result = match operation {
52
- Operation :: Add => {
53
- result + operands[ operation_index + 1 ]
54
- } ,
55
- Operation :: Mul => {
56
- result * operands[ operation_index + 1 ]
57
- } ,
63
+ Operation :: Add => result + operands[ operation_index + 1 ] ,
64
+ Operation :: Mul => result * operands[ operation_index + 1 ] ,
65
+ Operation :: Cat => {
66
+ // Just convert with a format string and count the digits to multiply by 10
67
+ let rhs = operands[ operation_index + 1 ] ;
68
+ let num_digits = format ! ( "{}" , rhs) ;
69
+ let mut result = result;
70
+ ( 0 ..num_digits. len ( ) ) . for_each ( |_| result *= 10 ) ;
71
+ result + rhs
72
+ }
58
73
} ;
59
74
60
75
if operation_index + 2 == operands. len ( ) {
@@ -66,33 +81,62 @@ fn try_operation(target: usize, result: usize, operands: &Vec<usize>, operation_
66
81
}
67
82
68
83
// Try add and then try multiply recursively
69
- if try_operation ( target, new_result, operands, operation_index + 1 , Operation :: Add ) {
84
+ if try_operation (
85
+ target,
86
+ new_result,
87
+ operands,
88
+ operation_index + 1 ,
89
+ Operation :: Add ,
90
+ cat_supported,
91
+ ) {
92
+ return true ;
93
+ }
94
+ if try_operation (
95
+ target,
96
+ new_result,
97
+ operands,
98
+ operation_index + 1 ,
99
+ Operation :: Mul ,
100
+ cat_supported,
101
+ ) {
70
102
return true ;
71
103
}
72
- if try_operation ( target, new_result, operands, operation_index + 1 , Operation :: Mul ) {
104
+ if cat_supported
105
+ && try_operation (
106
+ target,
107
+ new_result,
108
+ operands,
109
+ operation_index + 1 ,
110
+ Operation :: Cat ,
111
+ cat_supported,
112
+ )
113
+ {
73
114
return true ;
74
115
}
75
116
}
76
117
false
77
118
}
78
119
79
- fn calibrate ( equation : & Equation ) -> bool {
120
+ fn calibrate ( equation : & Equation , cat_supported : bool ) -> bool {
80
121
let target = equation. result ;
81
122
let operands = & equation. operands ;
82
123
let result = operands[ 0 ] ;
83
- if try_operation ( target, result, operands, 0 , Operation :: Add ) {
124
+ if try_operation ( target, result, operands, 0 , Operation :: Add , cat_supported) {
125
+ return true ;
126
+ }
127
+ if try_operation ( target, result, operands, 0 , Operation :: Mul , cat_supported) {
84
128
return true ;
85
129
}
86
- if try_operation ( target, result, operands, 0 , Operation :: Mul ) {
130
+ if cat_supported && try_operation ( target, result, operands, 0 , Operation :: Cat , cat_supported ) {
87
131
return true ;
88
132
}
89
133
false
90
134
}
91
135
92
- fn calibrate_all ( equations : & Vec < Equation > ) -> usize {
136
+ fn calibrate_all ( equations : & Vec < Equation > , cat_supported : bool ) -> usize {
93
137
let mut sum = 0 ;
94
138
for equation in equations {
95
- if calibrate ( equation) {
139
+ if calibrate ( equation, cat_supported ) {
96
140
sum += equation. result ;
97
141
}
98
142
}
@@ -103,17 +147,31 @@ fn calibrate_all(equations: &Vec<Equation>) -> usize {
103
147
104
148
#[ test]
105
149
fn test_prelim ( ) {
106
- let sum = calibrate_all ( & read_equations ( & get_input ( "prelim.txt" ) ) ) ;
150
+ let sum = calibrate_all ( & read_equations ( & get_input ( "prelim.txt" ) ) , false ) ;
107
151
assert_eq ! ( sum, 3749 ) ;
108
152
}
109
153
110
154
#[ test]
111
155
fn test_part1 ( ) {
112
- let sum = calibrate_all ( & read_equations ( & get_input ( "input.txt" ) ) ) ;
156
+ let sum = calibrate_all ( & read_equations ( & get_input ( "input.txt" ) ) , false ) ;
113
157
assert_eq ! ( sum, 20281182715321 ) ;
114
158
}
115
159
160
+ #[ test]
161
+ fn test_prelim2 ( ) {
162
+ let sum = calibrate_all ( & read_equations ( & get_input ( "prelim.txt" ) ) , true ) ;
163
+ assert_eq ! ( sum, 11387 ) ;
164
+ }
165
+
166
+ #[ test]
167
+ fn test_part2 ( ) {
168
+ let sum = calibrate_all ( & read_equations ( & get_input ( "input.txt" ) ) , true ) ;
169
+ assert_eq ! ( sum, 159490400628354 ) ;
170
+ }
171
+
116
172
fn main ( ) {
117
- calibrate_all ( & read_equations ( & get_input ( "prelim.txt" ) ) ) ;
118
- calibrate_all ( & read_equations ( & get_input ( "input.txt" ) ) ) ;
173
+ calibrate_all ( & read_equations ( & get_input ( "prelim.txt" ) ) , false ) ;
174
+ calibrate_all ( & read_equations ( & get_input ( "input.txt" ) ) , false ) ;
175
+ calibrate_all ( & read_equations ( & get_input ( "prelim.txt" ) ) , true ) ;
176
+ calibrate_all ( & read_equations ( & get_input ( "input.txt" ) ) , true ) ;
119
177
}
0 commit comments