11package org .ck .adventofcode .year2024 ;
22
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 ;
49import org .ck .adventofcode .util .AOCSolution ;
510import org .ck .codechallengelib .annotation .Solution ;
611
712@ Solution (
813 id = 20242401 ,
9- name = "Day 24: ? " ,
14+ name = "Day 24: Crossed Wires " ,
1015 url = "https://adventofcode.com/2024/day/24" ,
11- category = "2024" ,
12- solved = false )
16+ category = "2024" )
1317@ Solution (
1418 id = 20242402 ,
15- name = "Day 24: ? - Part 2" ,
19+ name = "Day 24: Crossed Wires - Part 2" ,
1620 url = "https://adventofcode.com/2024/day/24#part2" ,
1721 category = "2024" ,
1822 solved = false )
1923public 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]+)" );
2027
2128 @ Override
2229 protected void runPartOne (final Scanner in ) {
@@ -25,10 +32,205 @@ protected void runPartOne(final Scanner in) {
2532
2633 @ Override
2734 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 ;
29142 }
30143
31144 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+ }
33233 }
234+
235+ private record Swappable (String wireNumber , String one , String two ) {}
34236}
0 commit comments