Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 659e71a

Browse files
committed
Solve 2024 day 24 part 2 automatically
1 parent 5b54798 commit 659e71a

File tree

2 files changed

+103
-12
lines changed

2 files changed

+103
-12
lines changed

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

Lines changed: 99 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package eu.sim642.adventofcode2024
22

3+
import scala.annotation.tailrec
34
import scala.collection.mutable
45

56
object Day24 {
@@ -15,18 +16,23 @@ object Day24 {
1516
case Gate(lhs: String, op: Op, rhs: String)
1617
}
1718

19+
class CyclicCircuit extends RuntimeException
20+
1821
case class Circuit(wireMap: Map[String, Wire]) {
1922
def zValue: Long = {
2023
val memo = mutable.Map.empty[String, Boolean]
2124

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))
2430

25-
def evalWire(wire: Wire): Boolean = wire match {
31+
def evalWire(wire: Wire, called: Set[String]): Boolean = wire match {
2632
case Wire.Input(value) => value
2733
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)
3036
op match {
3137
case Op.And => left && right
3238
case Op.Or => left || right
@@ -39,10 +45,30 @@ object Day24 {
3945
.toSeq
4046
.sorted
4147
.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)
4349
})
4450
}
4551

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+
4672
def swapped(name1: String, name2: String): Circuit =
4773
Circuit(wireMap + (name1 -> wireMap(name2)) + (name2 -> wireMap(name1)))
4874

@@ -60,15 +86,75 @@ object Day24 {
6086

6187
def withXValue(value: Long): Circuit = withInputValue("x", value)
6288
def withYValue(value: Long): Circuit = withInputValue("y", value)
89+
90+
def add(xValue: Long, yValue: Long): Long =
91+
withXValue(xValue).withYValue(yValue).zValue
6392
}
6493

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+
65151
def parseInput(s: String): (String, Wire.Input) = s match {
66152
case s"$name: 0" => name -> Wire.Input(false)
67153
case s"$name: 1" => name -> Wire.Input(true)
68154
}
69155

70156
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)
72158
case s"$lhs OR $rhs -> $name" => name -> Wire.Gate(lhs, Op.Or, rhs)
73159
case s"$lhs XOR $rhs -> $name" => name -> Wire.Gate(lhs, Op.Xor, rhs)
74160
}
@@ -100,15 +186,16 @@ object Day24 {
100186
def main(args: Array[String]): Unit = {
101187
val circuit = parseCircuit(input)
102188
println(circuit.zValue)
189+
findWrongBits(circuit)
103190
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")
107194

108195
val circuit3 = circuit2.withXValue(0)
109-
println(circuit3.zValue)
196+
//println(circuit3.zValue)
110197

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(","))
112199
// part 2: gst,khg,nhn,tvb,vdc,z12,z21,z33 - correct
113200
}
114201
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,8 @@ class Day24Test extends AnyFunSuite {
7474
test("Part 1 input answer") {
7575
assert(parseCircuit(input).zValue == 51410244478064L)
7676
}
77+
78+
test("Part 2 input answer") {
79+
assert(findWrongBitsString(parseCircuit(input)) == "gst,khg,nhn,tvb,vdc,z12,z21,z33")
80+
}
7781
}

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /