Skip to content

Commit 7efddfd

Browse files
committed
Clean up 2024 day 24 part 2
1 parent 659e71a commit 7efddfd

File tree

2 files changed

+28
-38
lines changed

2 files changed

+28
-38
lines changed

src/main/scala/eu/sim642/adventofcode2024/Day24.scala

Lines changed: 27 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
package eu.sim642.adventofcode2024
22

3-
import scala.annotation.tailrec
43
import scala.collection.mutable
54

5+
import eu.sim642.adventofcodelib.IteratorImplicits._
6+
67
object Day24 {
78

89
enum Op {
@@ -16,15 +17,19 @@ object Day24 {
1617
case Gate(lhs: String, op: Op, rhs: String)
1718
}
1819

19-
class CyclicCircuit extends RuntimeException
20+
/**
21+
* Exception to indicate cyclic circuit evaluation.
22+
* When trying for swaps in part 2, cycles may be introduced, which otherwise (slowly) lead to StackOverflowError.
23+
*/
24+
class CircuitCycleException extends RuntimeException
2025

2126
case class Circuit(wireMap: Map[String, Wire]) {
2227
def zValue: Long = {
2328
val memo = mutable.Map.empty[String, Boolean]
2429

2530
def evalName(name: String, called: Set[String]): Boolean =
2631
if (called.contains(name))
27-
throw new CyclicCircuit
32+
throw new CircuitCycleException
2833
else
2934
memo.getOrElseUpdate(name, evalWire(wireMap(name), called + name))
3035

@@ -54,7 +59,7 @@ object Day24 {
5459

5560
def evalName(name: String, called: Set[String]): Set[String] =
5661
if (called.contains(name))
57-
throw new CyclicCircuit
62+
throw new CircuitCycleException
5863
else
5964
memo.getOrElseUpdate(name, evalWire(wireMap(name), called + name) + name)
6065

@@ -91,62 +96,57 @@ object Day24 {
9196
withXValue(xValue).withYValue(yValue).zValue
9297
}
9398

94-
def findWrongBits(circuit: Circuit): Seq[(String, String)] = {
95-
99+
def findWireSwaps(circuit: Circuit): Seq[(String, String)] = {
96100
def isCorrect(circuit: Circuit, i: Int): Boolean = {
97101
(for {
102+
// must also check previous bit to account for incoming carry
98103
xBit <- 0 to 3
99104
yBit <- 0 to 3
100105
xValue = xBit.toLong << i >> 1
101106
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)
107+
} yield {
108+
try circuit.add(xValue, yValue) == xValue + yValue
109+
catch case _: CircuitCycleException => false
110+
}).forall(identity)
104111
}
105112

106-
def helper(circuit: Circuit, i: Int, acc: Seq[(String, String)]): Seq[Seq[(String, String)]] = {
113+
def helper(circuit: Circuit, i: Int, acc: List[(String, String)]): Iterator[List[(String, String)]] = {
107114
if (acc.sizeIs > 4)
108-
Seq.empty
115+
Iterator.empty
109116
else if (i > 44)
110-
Seq(acc)
117+
Iterator.single(acc)
111118
else if (isCorrect(circuit, i))
112119
helper(circuit, i + 1, acc)
113120
else {
114-
println(i)
115121
val depsPrev = circuit.dependencies(s"z${i - 1}")
116122
val deps = circuit.dependencies(s"z$i")
117123
val depsNext = circuit.dependencies(s"z${i + 1}")
118124
val depsNext2 = circuit.dependencies(s"z${i + 2}")
119125
val wrong1 = ((deps -- depsPrev) ++ (depsNext -- deps)).filterNot(_.startsWith("x")).filterNot(_.startsWith("y"))
120126
val wrong2 = (depsNext2 -- depsPrev).filterNot(_.startsWith("x")).filterNot(_.startsWith("y"))
121-
println(wrong1)
122-
println(wrong2)
123127
val swaps =
124128
for {
125129
name1 <- wrong1
126130
name2 <- wrong2
131+
// order names in swap to avoid duplicate checking
127132
minName = if (name1 < name2) name1 else name2
128133
maxName = if (name1 < name2) name2 else name1
129134
} yield (minName, maxName)
130135
for {
131-
(name1, name2) <- swaps.toSeq
132-
//name2 <- wrong2
136+
swap@(name1, name2) <- swaps.iterator
133137
newCircuit = circuit.swapped(name1, name2)
134-
//() = println((name1, name2))
135-
if isCorrect(newCircuit, i - 1)
136138
if isCorrect(newCircuit, i)
137-
swap = (name1, name2)
138-
rest <- helper(newCircuit, i + 1, acc :+ swap)
139-
} yield rest
139+
newAcc <- helper(newCircuit, i + 1, swap :: acc)
140+
} yield newAcc
140141
}
141142
}
142143

143-
val all = helper(circuit, 0, Seq.empty)
144-
all.foreach(println)
145-
all.head
144+
val swapss = helper(circuit, 0, Nil)
145+
swapss.head
146146
}
147147

148-
def findWrongBitsString(circuit: Circuit): String =
149-
findWrongBits(circuit).flatMap({ case (a, b) => Seq(a, b)}).sorted.mkString(",")
148+
def findWireSwapsString(circuit: Circuit): String =
149+
findWireSwaps(circuit).flatMap({ case (name1, name2) => Seq(name1, name2) }).sorted.mkString(",")
150150

151151
def parseInput(s: String): (String, Wire.Input) = s match {
152152
case s"$name: 0" => name -> Wire.Input(false)
@@ -186,16 +186,6 @@ object Day24 {
186186
def main(args: Array[String]): Unit = {
187187
val circuit = parseCircuit(input)
188188
println(circuit.zValue)
189-
findWrongBits(circuit)
190-
val circuit2 = circuit.swapped("z21", "nhn").swapped("tvb", "khg").swapped("z33", "gst").swapped("z12", "vdc")
191-
//printCircuitDot(circuit2)
192-
//println(circuit2.zValue)
193-
//println("51401618891888")
194-
195-
val circuit3 = circuit2.withXValue(0)
196-
//println(circuit3.zValue)
197-
198-
//println(Seq("z21", "nhn", "tvb", "khg", "z33", "gst", "z12", "vdc").sorted.mkString(","))
199-
// part 2: gst,khg,nhn,tvb,vdc,z12,z21,z33 - correct
189+
println(findWireSwapsString(circuit))
200190
}
201191
}

src/test/scala/eu/sim642/adventofcode2024/Day24Test.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,6 @@ class Day24Test extends AnyFunSuite {
7676
}
7777

7878
test("Part 2 input answer") {
79-
assert(findWrongBitsString(parseCircuit(input)) == "gst,khg,nhn,tvb,vdc,z12,z21,z33")
79+
assert(findWireSwapsString(parseCircuit(input)) == "gst,khg,nhn,tvb,vdc,z12,z21,z33")
8080
}
8181
}

0 commit comments

Comments
 (0)