11package  eu .sim642 .adventofcode2024 
22
3+ import  scala .annotation .tailrec 
34import  scala .collection .mutable 
45
56object  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" 
6288 def  withYValue (value : Long ):  Circuit  =  withInputValue(" y" 
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" " y" 
120+  val  wrong2  =  (depsNext2 --  depsPrev).filterNot(_.startsWith(" x" " 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" " tvb" " khg" " z33" " gst" " 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" " ," 
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}
0 commit comments