11package de.ronny_h.aoc.year24.day24
22
33import de.ronny_h.aoc.AdventOfCode
4+ import de.ronny_h.aoc.extensions.toBoolean
45import de.ronny_h.aoc.extensions.toDigit
56
67fun main () = CrossedWires ().run (66055249060558 , 0 )
78
8- class CrossedWires : AdventOfCode <Long >(2024 , 24 ) {
9+ class CrossedWires : AdventOfCode <Long >(2024 , 24 ) {
910
10- class And : (Boolean , Boolean ) -> Boolean {
11+ class And : (Boolean , Boolean ) -> Boolean {
1112 override fun invoke (a : Boolean , b : Boolean ) = a && b
1213 override fun toString () = " AND"
1314 override fun equals (other : Any? ) = other is And
1415 override fun hashCode (): Int = javaClass.hashCode()
1516 }
16- class Or : (Boolean , Boolean ) -> Boolean {
17+
18+ class Or : (Boolean , Boolean ) -> Boolean {
1719 override fun invoke (a : Boolean , b : Boolean ) = a || b
1820 override fun toString () = " OR"
1921 override fun equals (other : Any? ) = other is Or
2022 override fun hashCode (): Int = javaClass.hashCode()
2123 }
22- class Xor : (Boolean , Boolean ) -> Boolean {
24+
25+ class Xor : (Boolean , Boolean ) -> Boolean {
2326 override fun invoke (a : Boolean , b : Boolean ) = a xor b
2427 override fun toString () = " XOR"
2528 override fun equals (other : Any? ) = other is Xor
@@ -39,7 +42,7 @@ class CrossedWires: AdventOfCode<Long>(2024, 24) {
3942 .map {
4043 val (term, result) = it.split(" -> " )
4144 val (in1, op, in2) = term.split(" " )
42- val operation = when (op) {
45+ val operation = when (op) {
4346 " AND" -> And ()
4447 " OR" -> Or ()
4548 " XOR" -> Xor ()
@@ -81,7 +84,86 @@ class CrossedWires: AdventOfCode<Long>(2024, 24) {
8184 }
8285
8386 override fun part2 (input : List <String >): Long {
84- TODO (" Not yet implemented" )
87+ // inputs: x00..x44, y00..y44
88+ // outputs: z00..z45
89+ val gates = parseGates(input)
90+ val wires = parseWires(input).associateBy(Wire ::name)
91+
92+ simulateGates(wires, gates)
93+ add(0 , 0 , wires, gates)
94+ add(" 1" .repeat(45 ).toLong(2 ), 0 , wires, gates)
95+ add(0 , " 1" .repeat(45 ).toLong(2 ), wires, gates)
96+ add(" 1" .repeat(45 ).toLong(2 ), " 1" .repeat(45 ).toLong(2 ), wires, gates)
97+
98+ return 0
99+ }
100+
101+ private fun add (
102+ x : Long ,
103+ y : Long ,
104+ wires : Map <String , Wire >,
105+ gates : List <Gate >
106+ ) {
107+ val modifiedWires = wires.toMutableMap()
108+ modifiedWires.putAll(x.toWires(" x" ))
109+ modifiedWires.putAll(y.toWires(" y" ))
110+ simulateGates(modifiedWires, gates)
111+ }
112+
113+ private fun Long.toWires (prefix : String ): Map <String , Wire > = toString(2 )
114+ .reversed()
115+ .padEnd(45 , ' 0' )
116+ .mapIndexed { i, digit ->
117+ Wire (prefix + i.toString().padStart(2 , ' 0' ), digit.toBoolean())
118+ }
119+ .associateBy(Wire ::name)
120+
121+ private fun simulateGates (
122+ wires : Map <String , Wire >,
123+ gates : List <Gate >
124+ ) {
125+ println (" --- simulating gates ---" )
126+ val x0 = wires.withPrefixAsDecimal(" x" )
127+ val y0 = wires.withPrefixAsDecimal(" y" )
128+
129+ val simulatedWires = wires.simulateGates(gates)
130+
131+ val x1 = simulatedWires.withPrefixAsDecimal(" x" )
132+ val y1 = simulatedWires.withPrefixAsDecimal(" y" )
133+
134+ val sumSimulatedBinary = simulatedWires.withPrefixAsBinary(" z" )
135+ val zWires = simulatedWires.withPrefixSortedByLSBFirst(" z" )
136+ val sumSimulated = sumSimulatedBinary.toLong(2 )
137+ val sumExpectedBinary = (x1 + y1).toString(2 ).padStart(46 , ' 0' )
138+
139+ // check that the input wires aren't modified
140+ check(x0 == x1)
141+ check(y0 == y1)
142+
143+ println (" inputs:" )
144+ println (" x=$x0 " )
145+ println (" y=$y0 " )
146+ println ()
147+ println (" expected : x+y=${x1 + y1} " )
148+ println (" simulated: z =$sumSimulated " )
149+ println ()
150+ println (" as binary:" )
151+ println (" expected : x+y=$sumExpectedBinary " )
152+ println (" simulated: z =$sumSimulatedBinary " )
153+
154+ val differentIndices = mutableListOf<Int >()
155+ for (i in sumSimulatedBinary.indices) {
156+ if (sumSimulatedBinary[i] != sumExpectedBinary[i]) {
157+ differentIndices.add(i)
158+ }
159+ }
160+ println (" different indices: $differentIndices (${differentIndices.size} )" )
161+
162+ val wrongWires = differentIndices.map { zWires[it].name }
163+ println (" zWires at these indices: $wrongWires " )
164+
165+ val gatesToChange = gates.filter { it.out in wrongWires }
166+ println (" gates to change: $gatesToChange " )
85167 }
86168}
87169
0 commit comments