1
+ import static com .github .pareronia .aoc .IntegerSequence .Range .rangeClosed ;
2
+ import static com .github .pareronia .aoc .StringOps .splitOnce ;
1
3
import static java .util .Objects .requireNonNull ;
2
4
import static java .util .function .Function .identity ;
3
5
import static java .util .stream .Collectors .joining ;
4
- import static java .util .stream .Collectors .toList ;
5
6
import static java .util .stream .Collectors .toMap ;
6
7
7
8
import java .util .Collection ;
8
- import java .util .HashSet ;
9
9
import java .util .List ;
10
10
import java .util .Map ;
11
- import java .util .Optional ;
12
11
import java .util .Set ;
12
+ import java .util .function .BiPredicate ;
13
+ import java .util .function .Predicate ;
13
14
14
- import com .github .pareronia .aoc .StringOps ;
15
15
import com .github .pareronia .aoc .StringOps .StringSplit ;
16
16
import com .github .pareronia .aoc .StringUtils ;
17
17
import com .github .pareronia .aoc .solution .Sample ;
18
18
import com .github .pareronia .aoc .solution .Samples ;
19
19
import com .github .pareronia .aoc .solution .SolutionBase ;
20
20
21
- public class AoC2024_24 extends SolutionBase <List < AoC2024_24 .Gate > , Long , String > {
21
+ public class AoC2024_24 extends SolutionBase <AoC2024_24 .Circuit , Long , String > {
22
22
23
23
private AoC2024_24 (final boolean debug ) {
24
24
super (debug );
@@ -33,67 +33,55 @@ public static final AoC2024_24 createDebug() {
33
33
}
34
34
35
35
@ Override
36
- protected List < Gate > parseInput (final List <String > inputs ) {
37
- return inputs . stream (). filter ( s -> ! s . isBlank ()). map ( Gate :: fromInput ). collect ( toList () );
36
+ protected Circuit parseInput (final List <String > inputs ) {
37
+ return Circuit . fromInput ( inputs );
38
38
}
39
39
40
- int part1 (final List <Gate > inputs , final String wire ) {
41
- final Circuit circuit = Circuit .of (inputs );
42
- return circuit .getValue (wire );
43
- }
44
-
45
40
@ Override
46
- public Long solvePart1 (final List <Gate > inputs ) {
47
- String ans = "" ;
48
- for (int i = 0 ; i <= 45 ; i ++) {
49
- try {
50
- ans = part1 (inputs , String .format ("z%02d" , i )) + ans ;
51
- } catch (final AssertionError e ) {
52
- }
53
- }
54
- return Long .parseLong (ans , 2 );
41
+ public Long solvePart1 (final Circuit circuit ) {
42
+ final int maxZ = circuit .getGates ().stream ()
43
+ .filter (gate -> gate .getName ().startsWith ("z" ))
44
+ .map (gate -> gate .getName ().substring (1 ))
45
+ .mapToInt (Integer ::parseInt )
46
+ .max ().getAsInt ();
47
+ return rangeClosed (maxZ , 0 , -1 ).intStream ()
48
+ .mapToLong (i -> ((1L << i )
49
+ * circuit .getValue ("z%02d" .formatted (i ))))
50
+ .sum ();
55
51
}
56
52
57
53
@ Override
58
- public String solvePart2 (final List <Gate > inputs ) {
59
- final List <Gate > gates = Circuit .of (inputs ).getGates ().stream ().filter (gate -> gate .op != AoC2024_24 .Gate .Op .SET ).toList ();
60
- final Set <String > swapped = new HashSet <>();
61
- for (final Gate gate : gates ) {
62
- if (gate .op == AoC2024_24 .Gate .Op .SET ) {
63
- continue ;
64
- }
65
- if (gate .name .startsWith ("z" )
66
- && gate .op != AoC2024_24 .Gate .Op .XOR
67
- && !gate .name .equals ("z45" )) {
68
- swapped .add (gate .name );
69
- }
70
- if (gate .op == AoC2024_24 .Gate .Op .XOR
54
+ public String solvePart2 (final Circuit circuit ) {
55
+ final Predicate <Gate > outputsToZExceptFirstOneAndNotXOR
56
+ = gate -> (gate .name .startsWith ("z" )
57
+ && gate .op != Gate .Op .XOR
58
+ && !gate .name .equals ("z45" ));
59
+ final Predicate <Gate > isXORNotConnectedToXorYorZ
60
+ = gate -> gate .op == Gate .Op .XOR
71
61
&& Set .of (gate .name , gate .in1 , gate .in2 ).stream ()
72
- .noneMatch (n -> n .startsWith ("x" )
73
- || n .startsWith ("y" )
74
- || n .startsWith ("z" ))) {
75
- swapped .add (gate .name );
76
- }
77
- if (gate .op == AoC2024_24 .Gate .Op .AND
78
- && !(gate .in1 .equals ("x00" ) || gate .in2 .equals ("x00" ))) {
79
- for (final Gate other : gates ) {
80
- if (other .op != AoC2024_24 .Gate .Op .OR
81
- && (Set .of (other .in1 , other .in2 ).contains (gate .name ))) {
82
- swapped .add (gate .name );
83
- }
84
- }
85
- }
86
- if (gate .op == AoC2024_24 .Gate .Op .XOR ) {
87
- for (final Gate other : gates ) {
88
- if (other .op == AoC2024_24 .Gate .Op .OR
89
- && (Set .of (other .in1 , other .in2 ).contains (gate .name ))) {
90
- swapped .add (gate .name );
91
- }
92
- }
93
- }
94
- }
95
- log (swapped );
96
- return swapped .stream ().sorted ().collect (joining ("," ));
62
+ .noneMatch (n -> n .startsWith ("x" )
63
+ || n .startsWith ("y" )
64
+ || n .startsWith ("z" ));
65
+ final BiPredicate <Gate , List <Gate >> isANDExceptLastWithAnOutputNotToOR
66
+ = (gate , others ) -> (gate .op == Gate .Op .AND
67
+ && !(gate .in1 .equals ("x00" ) || gate .in2 .equals ("x00" ))
68
+ && others .stream ().anyMatch (other -> other .op != Gate .Op .OR
69
+ && (Set .of (other .in1 , other .in2 ).contains (gate .name ))));
70
+ final BiPredicate <Gate , List <Gate >> isXORWithAnOutputToOR
71
+ = (gate , others ) -> (gate .op == Gate .Op .XOR
72
+ && others .stream ().anyMatch (other -> other .op == Gate .Op .OR
73
+ && (Set .of (other .in1 , other .in2 ).contains (gate .name ))));
74
+ final List <Gate > gates = circuit .getGates ().stream ()
75
+ .filter (gate -> gate .op != Gate .Op .SET )
76
+ .toList ();
77
+ return gates .stream ()
78
+ .filter (gate -> outputsToZExceptFirstOneAndNotXOR .test (gate )
79
+ || isXORNotConnectedToXorYorZ .test (gate )
80
+ || isANDExceptLastWithAnOutputNotToOR .test (gate , gates )
81
+ || isXORWithAnOutputToOR .test (gate , gates ))
82
+ .map (Gate ::getName )
83
+ .sorted ()
84
+ .collect (joining ("," ));
97
85
}
98
86
99
87
@ Override
@@ -170,7 +158,7 @@ public static void main(final String[] args) throws Exception {
170
158
tnw OR pbm -> gnj
171
159
""" ;
172
160
173
- static final class Gate implements Cloneable {
161
+ static final class Gate {
174
162
175
163
enum Op { SET , AND , OR , XOR }
176
164
@@ -197,38 +185,24 @@ protected Gate(
197
185
198
186
public static Gate fromInput (final String input ) {
199
187
if (input .contains (": " )) {
200
- final StringSplit splits = StringOps . splitOnce (input , ": " );
188
+ final StringSplit splits = splitOnce (input , ": " );
201
189
return Gate .set (splits .left (), splits .right ());
202
190
}
203
- final String [] splits = input .split (" -> " );
204
- if (splits [0 ].contains ("AND" )) {
205
- final String [] andSplits = splits [0 ].split (" AND " );
206
- return Gate .and (splits [1 ], andSplits [0 ], andSplits [1 ]);
207
- } else if (splits [0 ].contains ("XOR" )) {
208
- final String in = splits [0 ].substring (" XOR " .length ());
209
- final String [] xorSplits = splits [0 ].split (" XOR " );
210
- return Gate .xor (splits [1 ], xorSplits [0 ], xorSplits [1 ]);
211
- } else if (splits [0 ].contains ("OR" ) && !splits [0 ].contains ("XOR" )) {
212
- final String [] orSplits = splits [0 ].split (" OR " );
213
- return Gate .or (splits [1 ], orSplits [0 ], orSplits [1 ]);
191
+ final StringSplit splits = splitOnce (input , " -> " );
192
+ if (splits .left ().contains ("AND" )) {
193
+ final StringSplit andSplits = splitOnce (splits .left (), " AND " );
194
+ return Gate .and (splits .right (), andSplits .left (), andSplits .right ());
195
+ } else if (splits .left ().contains ("XOR" )) {
196
+ final StringSplit xorSplits = splitOnce (splits .left (), " XOR " );
197
+ return Gate .xor (splits .right (), xorSplits .left (), xorSplits .right ());
198
+ } else if (splits .left ().contains ("OR" ) && !splits .left ().contains ("XOR" )) {
199
+ final StringSplit orSplits = splitOnce (splits .left (), " OR " );
200
+ return Gate .or (splits .right (), orSplits .left (), orSplits .right ());
214
201
} else {
215
202
throw new IllegalArgumentException ();
216
203
}
217
204
}
218
205
219
- @ Override
220
- protected Gate clone () throws CloneNotSupportedException {
221
- return new Gate (this .name , this .in1 , this .in2 , this .op , this .arg );
222
- }
223
-
224
- public static Gate cloneGate (final Gate gate ) {
225
- try {
226
- return gate .clone ();
227
- } catch (final CloneNotSupportedException e ) {
228
- throw new RuntimeException (e );
229
- }
230
- }
231
-
232
206
public static Gate xor (final String name , final String in ) {
233
207
return new Gate (name , in , null , Op .XOR , null );
234
208
}
@@ -259,20 +233,10 @@ public Integer getResult() {
259
233
260
234
public Integer updateResult (final Integer in1 , final Integer in2 ) {
261
235
switch (this .op ) {
262
- case SET :
263
- this .result = in1 ;
264
- break ;
265
- case AND :
266
- this .result = in1 & in2 ;
267
- break ;
268
- case XOR :
269
- this .result = in1 ^ in2 ;
270
- break ;
271
- case OR :
272
- this .result = in1 | in2 ;
273
- break ;
274
- default :
275
- throw new IllegalStateException ();
236
+ case SET -> this .result = in1 ;
237
+ case AND -> this .result = in1 & in2 ;
238
+ case XOR -> this .result = in1 ^ in2 ;
239
+ case OR -> this .result = in1 | in2 ;
276
240
}
277
241
return this .result ;
278
242
}
@@ -281,35 +245,22 @@ public Integer updateResult(final Integer in1, final Integer in2) {
281
245
public String toString () {
282
246
final StringBuilder sb = new StringBuilder ();
283
247
switch (this .op ) {
284
- case SET :
285
- sb .append (this .in1 );
286
- break ;
287
- case AND :
288
- sb .append (this .in1 ).append (" AND " ).append (this .in2 );
289
- break ;
290
- case OR :
291
- sb .append (this .in1 ).append (" OR " ).append (this .in2 );
292
- break ;
293
- case XOR :
294
- sb .append (this .in1 ).append (" XOR " ).append (this .in2 );
295
- break ;
296
- default :
297
- throw new IllegalStateException ();
248
+ case SET -> sb .append (this .in1 );
249
+ case AND -> sb .append (this .in1 ).append (" AND " ).append (this .in2 );
250
+ case OR -> sb .append (this .in1 ).append (" OR " ).append (this .in2 );
251
+ case XOR -> sb .append (this .in1 ).append (" XOR " ).append (this .in2 );
298
252
}
299
253
return sb .toString ();
300
254
}
301
255
}
302
256
303
- private static final class Circuit {
304
- private final Map <String , Gate > gates ;
257
+ record Circuit (Map <String , Gate > gates ) {
305
258
306
- protected Circuit (final Map <String , AoC2024_24 .Gate > gates ) {
307
- this .gates = gates ;
308
- }
309
-
310
- public static Circuit of (final Collection <Gate > gates ) {
311
- return new Circuit (requireNonNull (gates ).stream ()
312
- .collect (toMap (Gate ::getName , identity ())));
259
+ public static Circuit fromInput (final List <String > inputs ) {
260
+ return new Circuit (inputs .stream ()
261
+ .filter (s -> !s .isBlank ())
262
+ .map (Gate ::fromInput )
263
+ .collect (toMap (Gate ::getName , identity ())));
313
264
}
314
265
315
266
public Collection <Gate > getGates () {
@@ -320,20 +271,6 @@ public Gate getGate(final String name) {
320
271
return this .gates .get (requireNonNull (name ));
321
272
}
322
273
323
- public void setGate (final String name , final Gate gate ) {
324
- this .gates .put (requireNonNull (name ), requireNonNull (gate ));
325
- }
326
-
327
- public Optional <Gate > getGateIn1 (final String name ) {
328
- final Gate gate = this .getGate (name );
329
- return Optional .ofNullable (gate .in1 ).map (this ::getGate );
330
- }
331
-
332
- public Optional <Gate > getGateIn2 (final String name ) {
333
- final Gate gate = this .getGate (name );
334
- return Optional .ofNullable (gate .in2 ).map (this ::getGate );
335
- }
336
-
337
274
public int getValue (final String name ) {
338
275
assert name != null && !name .isEmpty (): "name is empty" ;
339
276
if (StringUtils .isNumeric (name )) {
@@ -349,12 +286,5 @@ public int getValue(final String name) {
349
286
final Integer in2 = gate .in2 != null ? getValue (gate .in2 ) : null ;
350
287
return gate .updateResult (in1 , in2 );
351
288
}
352
-
353
- @ Override
354
- public String toString () {
355
- final StringBuilder builder = new StringBuilder ();
356
- builder .append ("Circuit [gates=" ).append (gates ).append ("]" );
357
- return builder .toString ();
358
- }
359
289
}
360
290
}
0 commit comments