1
1
package eu .sim642 .adventofcode2024
2
2
3
+ import scala .annotation .tailrec
3
4
import scala .collection .mutable
4
5
5
6
object Day24 {
@@ -15,18 +16,23 @@ object Day24 {
15
16
case Gate (lhs : String , op : Op , rhs : String )
16
17
}
17
18
19
+ class CyclicCircuit extends RuntimeException
20
+
18
21
case class Circuit (wireMap : Map [String , Wire ]) {
19
22
def zValue : Long = {
20
23
val memo = mutable.Map .empty[String , Boolean ]
21
24
22
- def evalName (name : String ): Boolean =
23
- memo.getOrElseUpdate(name, evalWire(wireMap(name)))
25
+ def evalName (name : String , called : Set [String ]): Boolean =
26
+ if (called.contains(name))
27
+ throw new CyclicCircuit
28
+ else
29
+ memo.getOrElseUpdate(name, evalWire(wireMap(name), called + name))
24
30
25
- def evalWire (wire : Wire ): Boolean = wire match {
31
+ def evalWire (wire : Wire , called : Set [ String ] ): Boolean = wire match {
26
32
case Wire .Input (value) => value
27
33
case Wire .Gate (lhs, op, rhs) =>
28
- val left = evalName(lhs)
29
- val right = evalName(rhs)
34
+ val left = evalName(lhs, called )
35
+ val right = evalName(rhs, called )
30
36
op match {
31
37
case Op .And => left && right
32
38
case Op .Or => left || right
@@ -39,10 +45,30 @@ object Day24 {
39
45
.toSeq
40
46
.sorted
41
47
.foldRight(0L )({ case (zName, acc) =>
42
- acc << 1 | (if (evalName(zName)) 1 else 0 )
48
+ acc << 1 | (if (evalName(zName, Set .empty )) 1 else 0 )
43
49
})
44
50
}
45
51
52
+ def dependencies (name : String ): Set [String ] = {
53
+ val memo = mutable.Map .empty[String , Set [String ]]
54
+
55
+ def evalName (name : String , called : Set [String ]): Set [String ] =
56
+ if (called.contains(name))
57
+ throw new CyclicCircuit
58
+ else
59
+ memo.getOrElseUpdate(name, evalWire(wireMap(name), called + name) + name)
60
+
61
+ def evalWire (wire : Wire , called : Set [String ]): Set [String ] = wire match {
62
+ case Wire .Input (value) => Set .empty
63
+ case Wire .Gate (lhs, op, rhs) =>
64
+ val left = evalName(lhs, called)
65
+ val right = evalName(rhs, called)
66
+ left ++ right
67
+ }
68
+
69
+ evalName(name, Set .empty)
70
+ }
71
+
46
72
def swapped (name1 : String , name2 : String ): Circuit =
47
73
Circuit (wireMap + (name1 -> wireMap(name2)) + (name2 -> wireMap(name1)))
48
74
@@ -60,15 +86,75 @@ object Day24 {
60
86
61
87
def withXValue (value : Long ): Circuit = withInputValue(" x" , value)
62
88
def withYValue (value : Long ): Circuit = withInputValue(" y" , value)
89
+
90
+ def add (xValue : Long , yValue : Long ): Long =
91
+ withXValue(xValue).withYValue(yValue).zValue
63
92
}
64
93
94
+ def findWrongBits (circuit : Circuit ): Seq [(String , String )] = {
95
+
96
+ def isCorrect (circuit : Circuit , i : Int ): Boolean = {
97
+ (for {
98
+ xBit <- 0 to 3
99
+ yBit <- 0 to 3
100
+ xValue = xBit.toLong << i >> 1
101
+ yValue = yBit.toLong << i >> 1
102
+ // if (try {circuit.dependencies("z45"); true} catch {case e: CyclicCircuit => false})
103
+ } yield try {circuit.add(xValue, yValue) == xValue + yValue} catch {case e : CyclicCircuit => false }).forall(identity)
104
+ }
105
+
106
+ def helper (circuit : Circuit , i : Int , acc : Seq [(String , String )]): Seq [Seq [(String , String )]] = {
107
+ if (acc.sizeIs > 4 )
108
+ Seq .empty
109
+ else if (i > 44 )
110
+ Seq (acc)
111
+ else if (isCorrect(circuit, i))
112
+ helper(circuit, i + 1 , acc)
113
+ else {
114
+ println(i)
115
+ val depsPrev = circuit.dependencies(s " z ${i - 1 }" )
116
+ val deps = circuit.dependencies(s " z $i" )
117
+ val depsNext = circuit.dependencies(s " z ${i + 1 }" )
118
+ val depsNext2 = circuit.dependencies(s " z ${i + 2 }" )
119
+ val wrong1 = ((deps -- depsPrev) ++ (depsNext -- deps)).filterNot(_.startsWith(" x" )).filterNot(_.startsWith(" y" ))
120
+ val wrong2 = (depsNext2 -- depsPrev).filterNot(_.startsWith(" x" )).filterNot(_.startsWith(" y" ))
121
+ println(wrong1)
122
+ println(wrong2)
123
+ val swaps =
124
+ for {
125
+ name1 <- wrong1
126
+ name2 <- wrong2
127
+ minName = if (name1 < name2) name1 else name2
128
+ maxName = if (name1 < name2) name2 else name1
129
+ } yield (minName, maxName)
130
+ for {
131
+ (name1, name2) <- swaps.toSeq
132
+ // name2 <- wrong2
133
+ newCircuit = circuit.swapped(name1, name2)
134
+ // () = println((name1, name2))
135
+ if isCorrect(newCircuit, i - 1 )
136
+ if isCorrect(newCircuit, i)
137
+ swap = (name1, name2)
138
+ rest <- helper(newCircuit, i + 1 , acc :+ swap)
139
+ } yield rest
140
+ }
141
+ }
142
+
143
+ val all = helper(circuit, 0 , Seq .empty)
144
+ all.foreach(println)
145
+ all.head
146
+ }
147
+
148
+ def findWrongBitsString (circuit : Circuit ): String =
149
+ findWrongBits(circuit).flatMap({ case (a, b) => Seq (a, b)}).sorted.mkString(" ," )
150
+
65
151
def parseInput (s : String ): (String , Wire .Input ) = s match {
66
152
case s " $name: 0 " => name -> Wire .Input (false )
67
153
case s " $name: 1 " => name -> Wire .Input (true )
68
154
}
69
155
70
156
def parseGate (s : String ): (String , Wire .Gate ) = s match {
71
- case s " $lhs AND $rhs -> $name" => name -> Wire .Gate (lhs, Op .And , rhs)
157
+ case s " $lhs AND $rhs -> $name" => name -> Wire .Gate (lhs, Op .And , rhs)
72
158
case s " $lhs OR $rhs -> $name" => name -> Wire .Gate (lhs, Op .Or , rhs)
73
159
case s " $lhs XOR $rhs -> $name" => name -> Wire .Gate (lhs, Op .Xor , rhs)
74
160
}
@@ -100,15 +186,16 @@ object Day24 {
100
186
def main (args : Array [String ]): Unit = {
101
187
val circuit = parseCircuit(input)
102
188
println(circuit.zValue)
189
+ findWrongBits(circuit)
103
190
val circuit2 = circuit.swapped(" z21" , " nhn" ).swapped(" tvb" , " khg" ).swapped(" z33" , " gst" ).swapped(" z12" , " vdc" )
104
- printCircuitDot(circuit2)
105
- println(circuit2.zValue)
106
- println(" 51401618891888" )
191
+ // printCircuitDot(circuit2)
192
+ // println(circuit2.zValue)
193
+ // println("51401618891888")
107
194
108
195
val circuit3 = circuit2.withXValue(0 )
109
- println(circuit3.zValue)
196
+ // println(circuit3.zValue)
110
197
111
- println(Seq (" z21" , " nhn" , " tvb" , " khg" , " z33" , " gst" , " z12" , " vdc" ).sorted.mkString(" ," ))
198
+ // println(Seq("z21", "nhn", "tvb", "khg", "z33", "gst", "z12", "vdc").sorted.mkString(","))
112
199
// part 2: gst,khg,nhn,tvb,vdc,z12,z21,z33 - correct
113
200
}
114
201
}
0 commit comments