1
1
package org .ck .adventofcode .year2024 ;
2
2
3
- import java .util .Scanner ;
3
+ import java .util .*;
4
+ import java .util .function .BinaryOperator ;
5
+ import java .util .function .Consumer ;
6
+ import java .util .regex .Matcher ;
7
+ import java .util .regex .Pattern ;
8
+ import java .util .stream .Collectors ;
4
9
import org .ck .adventofcode .util .AOCSolution ;
5
10
import org .ck .codechallengelib .annotation .Solution ;
6
11
7
12
@ Solution (
8
13
id = 20242401 ,
9
- name = "Day 24: ? " ,
14
+ name = "Day 24: Crossed Wires " ,
10
15
url = "https://adventofcode.com/2024/day/24" ,
11
- category = "2024" ,
12
- solved = false )
16
+ category = "2024" )
13
17
@ Solution (
14
18
id = 20242402 ,
15
- name = "Day 24: ? - Part 2" ,
19
+ name = "Day 24: Crossed Wires - Part 2" ,
16
20
url = "https://adventofcode.com/2024/day/24#part2" ,
17
21
category = "2024" ,
18
22
solved = false )
19
23
public class Day24 extends AOCSolution {
24
+ private static final Pattern PATTERN =
25
+ Pattern .compile (
26
+ "(?<one>[a-z0-9]+) (?<type>XOR|AND|OR) (?<two>[a-z0-9]+) -> (?<result>[a-z0-9]+)" );
20
27
21
28
@ Override
22
29
protected void runPartOne (final Scanner in ) {
@@ -25,10 +32,205 @@ protected void runPartOne(final Scanner in) {
25
32
26
33
@ Override
27
34
protected void runPartTwo (final Scanner in ) {
28
- run (in );
35
+ run2 (in );
36
+ }
37
+
38
+ private void run2 (final Scanner in ) {
39
+ final Map <String , Boolean > initialValues = new HashMap <>();
40
+ final Map <String , Boolean > outputs = new HashMap <>();
41
+ final List <String > rawGates = new ArrayList <>();
42
+
43
+ while (in .hasNextLine ()) {
44
+ final String [] line = in .nextLine ().split (": " );
45
+
46
+ if (line .length == 1 ) {
47
+ break ;
48
+ }
49
+
50
+ initialValues .put (line [0 ], "1" .equals (line [1 ]));
51
+ }
52
+
53
+ final List <String > inputWires =
54
+ initialValues .keySet ().stream ()
55
+ .map (inputWire -> inputWire .substring (1 ))
56
+ .sorted ()
57
+ .distinct ()
58
+ .toList ();
59
+
60
+ while (in .hasNextLine ()) {
61
+ rawGates .add (in .nextLine ());
62
+ }
63
+
64
+ long x = 0 ;
65
+ long y = 0 ;
66
+ for (final String inputWire : inputWires ) {
67
+ x <<= 1 ;
68
+ y <<= 1 ;
69
+
70
+ x += Boolean .TRUE .equals (initialValues .get ("x" + inputWire )) ? 1 : 0 ;
71
+ y += Boolean .TRUE .equals (initialValues .get ("y" + inputWire )) ? 1 : 0 ;
72
+ }
73
+
74
+ final long z = x + y ;
75
+ final String binaryZ = Long .toBinaryString (z );
76
+ final Map <String , Boolean > zWires = new HashMap <>();
77
+ final Queue <Swappable > swappables = new LinkedList <>();
78
+
79
+ boolean numberIsCorrect = false ;
80
+ while (!numberIsCorrect ) {
81
+ final Swappable swappable = swappables .poll ();
82
+
83
+ final Map <String , List <Gate >> currentGates = generateGates (rawGates , outputs , swappable );
84
+ numberIsCorrect = true ;
85
+
86
+ for (String inputWire : inputWires ) {
87
+ outputs .clear ();
88
+
89
+ final String xWire = "x" + inputWire ;
90
+ final String yWire = "y" + inputWire ;
91
+ final String zWire = "z" + inputWire ;
92
+
93
+ currentGates .get (xWire ).forEach (gate -> gate .accept (initialValues .get (xWire )));
94
+ currentGates .get (yWire ).forEach (gate -> gate .accept (initialValues .get (yWire )));
95
+
96
+ if (outputs .containsKey (zWire )) {
97
+ zWires .put (zWire , outputs .get (zWire ));
98
+
99
+ if (!outputs
100
+ .get (zWire )
101
+ .equals (binaryZ .charAt (binaryZ .length () - Integer .parseInt (inputWire ) - 1 ) == '1' )) {
102
+
103
+ Set <String > swapCandidates =
104
+ outputs .keySet ().stream ()
105
+ .filter (wire -> !zWire .equals (wire ))
106
+ .collect (Collectors .toSet ());
107
+
108
+ numberIsCorrect = false ;
109
+ break ;
110
+ }
111
+ } else {
112
+ // z wires don't seem to be swapped in my implementation, so I'll skip this
113
+ }
114
+ }
115
+ }
116
+
117
+ System .err .println (binaryZ );
118
+ System .err .println (
119
+ zWires .entrySet ().stream ()
120
+ .sorted (Map .Entry .<String , Boolean >comparingByKey ().reversed ())
121
+ .map (entry -> Boolean .TRUE .equals (entry .getValue ()) ? "1" : "0" )
122
+ .collect (Collectors .joining ()));
123
+ }
124
+
125
+ private Map <String , List <Gate >> generateGates (
126
+ final List <String > rawGates , final Map <String , Boolean > outputs , final Swappable swappable ) {
127
+ final Map <String , List <Gate >> gates = new HashMap <>();
128
+
129
+ for (final String rawGate : rawGates ) {
130
+ final Matcher matcher = PATTERN .matcher (rawGate );
131
+
132
+ if (matcher .matches ()) {
133
+ final Gate gate =
134
+ new Gate (matcher .group ("result" ), gates , outputs , getOperation (matcher .group ("type" )));
135
+
136
+ gates .computeIfAbsent (matcher .group ("one" ), k -> new ArrayList <>()).add (gate );
137
+ gates .computeIfAbsent (matcher .group ("two" ), k -> new ArrayList <>()).add (gate );
138
+ }
139
+ }
140
+
141
+ return gates ;
29
142
}
30
143
31
144
private void run (final Scanner in ) {
32
- print ("Whoopsie" );
145
+ final Map <String , Boolean > initialValues = new HashMap <>();
146
+ final Map <String , List <Gate >> gates = new HashMap <>();
147
+ final Map <String , Boolean > outputs = new HashMap <>();
148
+
149
+ while (in .hasNextLine ()) {
150
+ final String [] line = in .nextLine ().split (": " );
151
+
152
+ if (line .length == 1 ) {
153
+ break ;
154
+ }
155
+
156
+ initialValues .put (line [0 ], "1" .equals (line [1 ]));
157
+ }
158
+
159
+ while (in .hasNextLine ()) {
160
+ final Matcher matcher = PATTERN .matcher (in .nextLine ());
161
+
162
+ if (matcher .matches ()) {
163
+ final Gate gate =
164
+ new Gate (matcher .group ("result" ), gates , outputs , getOperation (matcher .group ("type" )));
165
+
166
+ gates .computeIfAbsent (matcher .group ("one" ), k -> new ArrayList <>()).add (gate );
167
+ gates .computeIfAbsent (matcher .group ("two" ), k -> new ArrayList <>()).add (gate );
168
+ }
169
+ }
170
+
171
+ for (final String gate : initialValues .keySet ()) {
172
+ gates .get (gate ).forEach (function -> function .accept (initialValues .get (gate )));
173
+ }
174
+
175
+ long result = 0 ;
176
+
177
+ final List <String > outputGates =
178
+ outputs .keySet ().stream ()
179
+ .filter (gate -> gate .startsWith ("z" ))
180
+ .sorted (Comparator .reverseOrder ())
181
+ .toList ();
182
+ for (final String gate : outputGates ) {
183
+ result <<= 1 ;
184
+ if (Boolean .TRUE .equals (outputs .get (gate ))) {
185
+ ++result ;
186
+ }
187
+ }
188
+
189
+ print (result );
190
+ }
191
+
192
+ private BinaryOperator <Boolean > getOperation (final String type ) {
193
+ return switch (type ) {
194
+ case "AND" -> (one , two ) -> one && two ;
195
+ case "OR" -> (one , two ) -> one || two ;
196
+ case "XOR" -> (one , two ) -> one ^ two ;
197
+ default -> throw new IllegalStateException ("Unexpected operation: " + type );
198
+ };
199
+ }
200
+
201
+ private static class Gate implements Consumer <Boolean > {
202
+ private final String resultGate ;
203
+ private final Map <String , List <Gate >> gates ;
204
+ private final Map <String , Boolean > outputs ;
205
+ private final BinaryOperator <Boolean > operation ;
206
+
207
+ private Boolean one ;
208
+
209
+ public Gate (
210
+ final String resultGate ,
211
+ final Map <String , List <Gate >> gates ,
212
+ final Map <String , Boolean > outputs ,
213
+ final BinaryOperator <Boolean > operation ) {
214
+ this .resultGate = resultGate ;
215
+ this .gates = gates ;
216
+ this .outputs = outputs ;
217
+ this .operation = operation ;
218
+ }
219
+
220
+ @ Override
221
+ public void accept (final Boolean input ) {
222
+ if (one == null ) {
223
+ one = input ;
224
+ } else {
225
+ final Boolean result = operation .apply (one , input );
226
+ outputs .put (resultGate , result );
227
+
228
+ if (gates .containsKey (resultGate )) {
229
+ gates .get (resultGate ).forEach (function -> function .accept (result ));
230
+ }
231
+ }
232
+ }
33
233
}
234
+
235
+ private record Swappable (String wireNumber , String one , String two ) {}
34
236
}
0 commit comments