Skip to content

Commit

Permalink
Clean up 2024 day 24 part 2
Browse files Browse the repository at this point in the history
  • Loading branch information
sim642 committed Dec 24, 2024
1 parent 659e71a commit 7efddfd
Show file tree
Hide file tree
Showing 2 changed files with 28 additions and 38 deletions.
64 changes: 27 additions & 37 deletions src/main/scala/eu/sim642/adventofcode2024/Day24.scala
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
package eu.sim642.adventofcode2024

import scala.annotation.tailrec
import scala.collection.mutable

import eu.sim642.adventofcodelib.IteratorImplicits._

object Day24 {

enum Op {
Expand All @@ -16,15 +17,19 @@ object Day24 {
case Gate(lhs: String, op: Op, rhs: String)
}

class CyclicCircuit extends RuntimeException
/**
* Exception to indicate cyclic circuit evaluation.
* When trying for swaps in part 2, cycles may be introduced, which otherwise (slowly) lead to StackOverflowError.
*/
class CircuitCycleException extends RuntimeException

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

def evalName(name: String, called: Set[String]): Boolean =
if (called.contains(name))
throw new CyclicCircuit
throw new CircuitCycleException
else
memo.getOrElseUpdate(name, evalWire(wireMap(name), called + name))

Expand Down Expand Up @@ -54,7 +59,7 @@ object Day24 {

def evalName(name: String, called: Set[String]): Set[String] =
if (called.contains(name))
throw new CyclicCircuit
throw new CircuitCycleException
else
memo.getOrElseUpdate(name, evalWire(wireMap(name), called + name) + name)

Expand Down Expand Up @@ -91,62 +96,57 @@ object Day24 {
withXValue(xValue).withYValue(yValue).zValue
}

def findWrongBits(circuit: Circuit): Seq[(String, String)] = {

def findWireSwaps(circuit: Circuit): Seq[(String, String)] = {
def isCorrect(circuit: Circuit, i: Int): Boolean = {
(for {
// must also check previous bit to account for incoming carry
xBit <- 0 to 3
yBit <- 0 to 3
xValue = xBit.toLong << i >> 1
yValue = yBit.toLong << i >> 1
//if (try {circuit.dependencies("z45"); true} catch {case e: CyclicCircuit => false})
} yield try {circuit.add(xValue, yValue) == xValue + yValue} catch {case e: CyclicCircuit => false}).forall(identity)
} yield {
try circuit.add(xValue, yValue) == xValue + yValue
catch case _: CircuitCycleException => false
}).forall(identity)
}

def helper(circuit: Circuit, i: Int, acc: Seq[(String, String)]): Seq[Seq[(String, String)]] = {
def helper(circuit: Circuit, i: Int, acc: List[(String, String)]): Iterator[List[(String, String)]] = {
if (acc.sizeIs > 4)
Seq.empty
Iterator.empty
else if (i > 44)
Seq(acc)
Iterator.single(acc)
else if (isCorrect(circuit, i))
helper(circuit, i + 1, acc)
else {
println(i)
val depsPrev = circuit.dependencies(s"z${i - 1}")
val deps = circuit.dependencies(s"z$i")
val depsNext = circuit.dependencies(s"z${i + 1}")
val depsNext2 = circuit.dependencies(s"z${i + 2}")
val wrong1 = ((deps -- depsPrev) ++ (depsNext -- deps)).filterNot(_.startsWith("x")).filterNot(_.startsWith("y"))
val wrong2 = (depsNext2 -- depsPrev).filterNot(_.startsWith("x")).filterNot(_.startsWith("y"))
println(wrong1)
println(wrong2)
val swaps =
for {
name1 <- wrong1
name2 <- wrong2
// order names in swap to avoid duplicate checking
minName = if (name1 < name2) name1 else name2
maxName = if (name1 < name2) name2 else name1
} yield (minName, maxName)
for {
(name1, name2) <- swaps.toSeq
//name2 <- wrong2
swap@(name1, name2) <- swaps.iterator
newCircuit = circuit.swapped(name1, name2)
//() = println((name1, name2))
if isCorrect(newCircuit, i - 1)
if isCorrect(newCircuit, i)
swap = (name1, name2)
rest <- helper(newCircuit, i + 1, acc :+ swap)
} yield rest
newAcc <- helper(newCircuit, i + 1, swap :: acc)
} yield newAcc
}
}

val all = helper(circuit, 0, Seq.empty)
all.foreach(println)
all.head
val swapss = helper(circuit, 0, Nil)
swapss.head
}

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

def parseInput(s: String): (String, Wire.Input) = s match {
case s"$name: 0" => name -> Wire.Input(false)
Expand Down Expand Up @@ -186,16 +186,6 @@ object Day24 {
def main(args: Array[String]): Unit = {
val circuit = parseCircuit(input)
println(circuit.zValue)
findWrongBits(circuit)
val circuit2 = circuit.swapped("z21", "nhn").swapped("tvb", "khg").swapped("z33", "gst").swapped("z12", "vdc")
//printCircuitDot(circuit2)
//println(circuit2.zValue)
//println("51401618891888")

val circuit3 = circuit2.withXValue(0)
//println(circuit3.zValue)

//println(Seq("z21", "nhn", "tvb", "khg", "z33", "gst", "z12", "vdc").sorted.mkString(","))
// part 2: gst,khg,nhn,tvb,vdc,z12,z21,z33 - correct
println(findWireSwapsString(circuit))
}
}
2 changes: 1 addition & 1 deletion src/test/scala/eu/sim642/adventofcode2024/Day24Test.scala
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,6 @@ class Day24Test extends AnyFunSuite {
}

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

0 comments on commit 7efddfd

Please sign in to comment.