1
- use std:: collections:: { HashMap , VecDeque } ;
1
+ use std:: collections:: { HashMap , HashSet , VecDeque } ;
2
2
use std:: fs:: { self , File } ;
3
3
use std:: io:: { BufWriter , Write } ;
4
4
@@ -158,9 +158,60 @@ fn main() {
158
158
println ! ( "{}" , total1) ;
159
159
160
160
// part 2
161
- let x = get_value ( & wires, "x" ) ;
162
- let y = get_value ( & wires, "y" ) ;
161
+ // try to find broken nodes by checking common patterns (this is basically
162
+ // what I've done visually)
163
+ let mut edges: HashMap < & str , Vec < & str > > = HashMap :: new ( ) ;
164
+ for g in & gates {
165
+ edges. entry ( g. a ) . or_default ( ) . push ( g. out ) ;
166
+ edges. entry ( g. b ) . or_default ( ) . push ( g. out ) ;
167
+ }
168
+
169
+ let mut broken_nodes = HashSet :: new ( ) ;
170
+ for g in & gates {
171
+ // z nodes must be XOR (except for the last one, z45)
172
+ if g. out . starts_with ( "z" ) && g. out != "z45" && g. logic != Logic :: Xor {
173
+ broken_nodes. insert ( g. out ) ;
174
+ }
175
+ // z nodes must not be inputs of other nodes
176
+ if g. a . starts_with ( "z" ) {
177
+ broken_nodes. insert ( g. a ) ;
178
+ }
179
+ if g. b . starts_with ( "z" ) {
180
+ broken_nodes. insert ( g. b ) ;
181
+ }
182
+
183
+ // inputs of XOR nodes (except for z nodes) must be x and y nodes
184
+ if g. logic == Logic :: Xor
185
+ && !g. out . starts_with ( "z" )
186
+ && !( ( g. a . starts_with ( "x" ) && g. b . starts_with ( "y" ) )
187
+ || ( g. a . starts_with ( "y" ) && g. b . starts_with ( "x" ) ) )
188
+ {
189
+ broken_nodes. insert ( g. out ) ;
190
+ }
163
191
192
+ // XOR nodes (except z nodes) must always be input of exactly two
193
+ // other nodes
194
+ if g. logic == Logic :: Xor && !g. out . starts_with ( "z" ) && edges[ g. out ] . len ( ) != 2 {
195
+ broken_nodes. insert ( g. out ) ;
196
+ }
197
+
198
+ // AND nodes must always be input of exactly one other node (except
199
+ // the very first one wired to x00 and y00)
200
+ if g. logic == Logic :: And
201
+ && !g. out . starts_with ( "z" )
202
+ && edges[ g. out ] . len ( ) != 1
203
+ && !( ( g. a == "x00" && g. b == "y00" ) || ( g. a == "y00" && g. b == "x00" ) )
204
+ {
205
+ broken_nodes. insert ( g. out ) ;
206
+ }
207
+ }
208
+
209
+ // this should be the answer:
210
+ let mut broken_nodes = broken_nodes. into_iter ( ) . collect :: < Vec < _ > > ( ) ;
211
+ broken_nodes. sort ( ) ;
212
+ println ! ( "{}" , broken_nodes. join( "," ) ) ;
213
+
214
+ // hard-coded answer for my puzzle input
164
215
let renames = HashMap :: from ( [
165
216
// 1
166
217
( "kqh" , "ddn" ) ,
@@ -176,11 +227,13 @@ fn main() {
176
227
( "wrc" , "z34" ) ,
177
228
] ) ;
178
229
230
+ let x = get_value ( & wires, "x" ) ;
231
+ let y = get_value ( & wires, "y" ) ;
179
232
let total2 = run ( & wires, & gates, & renames) ;
180
233
if total2 == x + y {
181
- let mut broken_wires = renames. keys ( ) . copied ( ) . collect :: < Vec < _ > > ( ) ;
182
- broken_wires . sort ( ) ;
183
- println ! ( "{}" , broken_wires . join ( "," ) ) ;
234
+ let mut broken_nodes2 = renames. keys ( ) . copied ( ) . collect :: < Vec < _ > > ( ) ;
235
+ broken_nodes2 . sort ( ) ;
236
+ assert_eq ! ( broken_nodes , broken_nodes2 ) ;
184
237
} else {
185
238
panic ! ( "Unsolvable" ) ;
186
239
}
0 commit comments