Day 24 ... overfit

This commit is contained in:
Christian
2024-12-28 14:15:13 +01:00
parent 3c6824e070
commit 76367959ae
4 changed files with 563 additions and 0 deletions

View File

@@ -26,6 +26,7 @@ val solvers = Map[Int, Solver](
21 -> Day21, 21 -> Day21,
22 -> Day22, 22 -> Day22,
23 -> Day23, 23 -> Day23,
24 -> Day24,
25 -> Day25 25 -> Day25
) )

View File

@@ -0,0 +1,247 @@
package dev.ctsk.aoc.days
import dev.ctsk.aoc.*
import scala.collection.mutable
object Day24 extends Solver(24):
extension (s: String)
def binLong: Long = s.foldLeft(0L)((acc, c) => (acc << 1) + c.asDigit)
enum Op(val f: Int => Int => Int):
case AND extends Op(x => y => x & y)
case OR extends Op(x => y => x | y)
case XOR extends Op(x => y => x ^ y)
case class Gate(op: Op, lhs: String, rhs: String)
object Gate:
def of(op: Op, lhs: String, rhs: String): Gate =
Gate(op, Seq(lhs, rhs).min, Seq(lhs, rhs).max)
override def run(input: os.ReadablePath): (Timings, Solution) =
val Array(inits_, wires_) = os.read(input).split("\n\n")
val inits = inits_.linesIterator
.map(_.split(": "))
.map { case Array(id, value) => (id, value.toInt) }
.toMap
val wires = wires_.linesIterator
.map(_.split(" "))
.map { case Array(in1, op, in2, _, out) =>
(out, Gate.of(Op.valueOf(op), in1, in2))
}
.toArray
val outs = wires.toMap
val ins = mutable.Map.from(wires.map(_.swap))
def tag(t: Char)(i: Int): String = f"$t$i%02d"
val x = tag('x'); val y = tag('y'); val z = tag('z')
def resolve_(id: String, f: String => Int): Int =
outs.get(id) match
case Some(gate) => gate.op.f(f(gate.lhs))(f(gate.rhs))
case _ => inits(id)
val resolve = Memo.Y(resolve_)
val p1 = timed { (0 to 45).reverse.map(z).map(resolve).mkString.binLong }
val p2 = timed {
val renames = mutable.Map.empty[String, String]
def rename(a: String, b: String): Unit =
renames(a) = b
renames(b) = a
def re(a: String): String = renames.getOrElse(a, a)
def lookup(gate: Gate): Option[String] =
ins.get(Gate.of(gate.op, re(gate.lhs), re(gate.rhs)))
var carry = ins(Gate.of(Op.AND, x(0), y(0)))
for i <- 1 to 44
do
println((i, carry))
val x_ = x(i)
val y_ = y(i)
val x_y_xor = lookup(Gate.of(Op.XOR, x_, y_)).get
val x_y_and = lookup(Gate.of(Op.AND, x_, y_)).get
val out = lookup(Gate.of(Op.XOR, x_y_xor, carry)) match
case Some(out) => out
case None =>
rename(x_y_xor, x_y_and)
lookup(Gate.of(Op.XOR, x_y_xor, carry)).get
if out != z(i) then rename(out, z(i))
val pre_carry = lookup(Gate.of(Op.AND, carry, x_y_xor)).get
carry = lookup(Gate.of(Op.OR, pre_carry, x_y_and)).get
renames.keys.toArray.sorted.mkString(",")
}
(
Timings(0, p1._1, p2._1),
Solution(Long.box(p1._2), p2._2)
)
// def construct_(id: String, f: String => Node): Node =
// wires.get(id) match
// case Some(l, r, op) => Node.Inner(id, Op.valueOf(op), f(l), f(r))
// case None => Node.Leaf(id)
// val construct = Memo.Y(construct_)
// val ends = wires.keySet.map(construct)
// val nodes = ends ++
// ends.collect { case Node.Inner(_, _, l, r) => Set(l, r) }.flatten
// def downstream_(node: Node): Set[Node] =
// nodes.collect {
// case inner: Node.Inner if inner.lhs.id == node.id => inner
// case inner: Node.Inner if inner.rhs.id == node.id => inner
// }
// val downstream = Memo(downstream_)
// def tag(t: Char)(i: Int): String = f"$t$i%02d"
// val x = tag('x');
// val y = tag('y');
// val z = tag('z');
// var lastCarry = ends.find(op(Op.AND, leaf(x(0)), leaf(y(0)))).get
// for i <- 1 to 44 do
// val out = op(Op.XOR, op(Op.XOR, leaf(x(i)), leaf(y(i))), _ => true)
// val mkCarry = op(
// Op.OR,
// op(Op.AND, leaf(x(i)), leaf(y(i))),
// op(
// Op.AND,
// op(Op.XOR, leaf(x(i)), leaf(y(i))),
// {
// case Node.Inner(id, _, _, _) => id == lastCarry.id
// case _ => false
// }
// )
// )
//
// ends
// .find(out) match
// case Some(node) => ()
// case None =>
// println(
// (
// z(i),
// wires(z(i)),
// ends.find(end =>
// op(Op.XOR, leaf(x(i)), leaf(y(i)))(construct(end))
// )
// )
// )
//
// def dependencies_(id: String, f: String => Set[String]): Set[String] =
// wires.get(id) match
// case Some(in1, in2, op) => f(in1) ++ f(in2)
// case None => Set(id)
// val dependencies = Memo.Y(dependencies_)
//
// val allDeps = wires.keySet.groupBy(dependencies)
// val carries = wires.filter((k, v) => v._3 == "OR").keySet
// val xs = (0 to 44).map(x).toSet
// val ys = (0 to 44).map(y).toSet
// val zs = (0 to 45).map(z).toSet
// (zs - "z45")
// def tag(i: Int): (String, String) =
// if i == 0
// then
// val candidates = revDependencies(Set("x00", "y00"))
// val output = candidates.find(wires(_)._3 == "XOR")
// val carry = candidates.find(wires(_)._3 == "AND")
// (output, carry)
// else
// val candidates = revDependencies(Set("x00", "y00"))
// val (pOutput, pCarry) = tag(i - 1)
// dependencies()
//
// def resolve_(id: String, f: String => Int): Int =
// wires.get(id) match
// case Some(in1, in2, "XOR") => f(in1) ^ f(in2)
// case Some(in1, in2, "OR") => f(in1) | f(in2)
// case Some(in1, in2, "AND") => f(in1) & f(in2)
// case _ => inits(id)
// val resolve = Memo.Y(resolve_)
//
// val p1 = timed { (0 to 45).reverse.map(z).map(resolve).mkString.binLong }
//
// val clear =
// (for
// i <- 0 to 44
// v <- Seq("x", "y")
// yield f"$v${i}%02d" -> 0).toMap
// for i <- 0 to 44 do
// for
// y <- 0 to 1
// x <- 0 to 1
// do
// val z = resolve(
// clear ++
// Seq(
// f"y${i}%02d" -> y,
// f"x${i}%02d" -> x
// ).toMap,
// f"z${i}%02d"
// )
// val carry = resolve(
// clear ++ Seq(
// f"y${i}%02d" -> y,
// f"x${i}%02d" -> x
// ).toMap,
// f"z${i + 1}%02d"
// )
//
// if z != (x ^ y) then println(f"z$i")
// if carry != (x & y) then println(f"carry$i")
// assert(z == (x ^ y))
// assert(carry == (x & y))
// val outs = wires.keySet
// .filter(_(0) == 'z')
// .map(out => (out, resolve(out)))
// .toArray
// .sorted
// .map(_._2)
//
// wires.foreach {
// case (id, (in1, in2, op)) =>
// val col = op match
// case "XOR" => "[color=\"red\"]"
// case "OR" => "[color=\"blue\"]"
// case "AND" => "[color=\"green\"]"
// println(f"$in1 -> $id $col")
// println(f"$in2 -> $id $col")
// }
// println(
// outs.mkString.reverse.foldLeft(0L)((acc, c) => (acc << 1) + c.asDigit)
// )
// enum Op { case AND, OR, XOR }
//
// enum Node:
// case Inner(op: Op, lhs: Node, rhs: Node)
// case Leaf(id: String)
// def id: String = this match
// case inner: Inner => inner.id
// case leaf: Leaf => leaf.id
//
// def op(op: Op, l: Node => Boolean, r: Node => Boolean)(node: Node): Boolean =
// node match
// case Node.Inner(_, inner, lhs, rhs) =>
// op == inner && (l(lhs) && r(rhs) || l(rhs) && r(lhs))
// case Node.Leaf(_) => false
//
// def leaf(id: String)(node: Node): Boolean =
// node match
// case Node.Leaf(leaf) => leaf == id
// case _ => false

2
data/24.ans Normal file
View File

@@ -0,0 +1,2 @@
51837135476040
hjf,kdh,kpp,sgj,vss,z14,z31,z35

313
data/24.in Normal file
View File

@@ -0,0 +1,313 @@
x00: 1
x01: 0
x02: 0
x03: 1
x04: 1
x05: 1
x06: 0
x07: 0
x08: 1
x09: 1
x10: 0
x11: 1
x12: 0
x13: 0
x14: 1
x15: 1
x16: 1
x17: 1
x18: 0
x19: 0
x20: 0
x21: 0
x22: 1
x23: 1
x24: 1
x25: 1
x26: 1
x27: 1
x28: 0
x29: 1
x30: 1
x31: 0
x32: 1
x33: 0
x34: 0
x35: 0
x36: 0
x37: 1
x38: 1
x39: 0
x40: 0
x41: 0
x42: 0
x43: 1
x44: 1
y00: 1
y01: 1
y02: 1
y03: 1
y04: 0
y05: 0
y06: 0
y07: 0
y08: 0
y09: 1
y10: 0
y11: 1
y12: 0
y13: 0
y14: 1
y15: 0
y16: 0
y17: 0
y18: 0
y19: 1
y20: 0
y21: 0
y22: 0
y23: 0
y24: 0
y25: 1
y26: 1
y27: 0
y28: 1
y29: 0
y30: 1
y31: 0
y32: 1
y33: 1
y34: 0
y35: 1
y36: 1
y37: 1
y38: 0
y39: 1
y40: 0
y41: 1
y42: 1
y43: 0
y44: 1
x07 AND y07 -> ncs
y24 AND x24 -> wrf
x19 XOR y19 -> tsm
x40 XOR y40 -> svt
rjf OR src -> dfv
fsf XOR fgs -> z44
mhc AND jqd -> qgn
nrr XOR sms -> kpp
y20 AND x20 -> ngc
y21 AND x21 -> hbc
sgj OR ptb -> rqf
hbc OR wdr -> gjn
tks XOR sbg -> z23
ddh AND tnm -> hgg
hsf OR bjw -> vbb
x15 XOR y15 -> vqs
x10 AND y10 -> dtm
vqs XOR vss -> z15
x29 XOR y29 -> mgd
srg OR cwb -> qtn
nmb OR mbk -> z45
dhs OR njq -> tng
jfw OR jrf -> vpd
x07 XOR y07 -> gck
tdw XOR vrk -> z03
y11 AND x11 -> ffw
x16 XOR y16 -> bth
x39 XOR y39 -> tnm
cfg AND ngh -> jrq
vpd AND mvn -> hbj
rgp XOR bth -> z16
qtn AND cjd -> vrv
x14 AND y14 -> cgt
dwh XOR hsk -> z24
tgp XOR dkh -> z13
y26 XOR x26 -> cfg
cpc XOR nbm -> z42
y42 XOR x42 -> cpc
x17 XOR y17 -> cjd
rqf XOR pqn -> z36
x27 AND y27 -> nwg
bcq AND hnk -> vjp
tks AND sbg -> wqr
wvr OR skq -> gmw
cwm AND tpv -> pqw
x41 AND y41 -> tqh
jcw AND wpk -> sbr
tgp AND dkh -> tbh
wrg XOR nwq -> z38
y32 XOR x32 -> gds
bmn OR hbj -> msb
wps XOR mtn -> z33
ncs OR pjf -> sws
wqr OR tqk -> dwh
x31 AND y31 -> pwg
y12 XOR x12 -> jcw
nrr AND sms -> z31
x38 AND y38 -> npd
y02 AND x02 -> fwt
y37 AND x37 -> rnc
fwt OR vtm -> tdw
x38 XOR y38 -> nwq
gds AND ghr -> ckd
ffw OR nfb -> wpk
ctv XOR wht -> z05
y11 XOR x11 -> cmg
y05 XOR x05 -> ctv
jhw XOR tcv -> z18
wrf OR gnt -> rmw
y01 AND x01 -> tnr
x36 XOR y36 -> pqn
gjq OR dfg -> skp
x40 AND y40 -> ptg
y39 AND x39 -> dqn
bjb OR hjf -> sbg
rrn OR rpt -> qfs
ctv AND wht -> dhs
sgs AND rsb -> ccw
rmw XOR psg -> z25
y24 XOR x24 -> hsk
bgd XOR msb -> z10
y17 AND x17 -> fvv
y22 AND x22 -> kdh
qfs AND rfv -> fgp
wds AND fps -> rhr
y18 XOR x18 -> tcv
ttd AND nhg -> tfw
bbc AND jkb -> ptb
djn OR tnr -> cpb
y35 XOR x35 -> bbc
tfw OR cgt -> z14
rgp AND bth -> srg
dwh AND hsk -> gnt
pqw OR ngc -> frt
y25 XOR x25 -> psg
y13 XOR x13 -> tgp
x30 XOR y30 -> rbw
vrv OR fvv -> jhw
skp XOR mgd -> z29
cmg XOR ntv -> z11
vjr XOR vbb -> z04
gkj XOR sws -> z08
x20 XOR y20 -> tpv
ntv AND cmg -> nfb
x32 AND y32 -> tdk
wmr AND cpb -> vtm
x19 AND y19 -> jps
jhw AND tcv -> rqv
y27 XOR x27 -> bcq
x34 AND y34 -> hdk
wqc XOR qtf -> z01
wgk OR sbr -> dkh
x43 AND y43 -> kdb
y04 XOR x04 -> vjr
rmw AND psg -> fgg
gkj AND sws -> jfw
cwm XOR tpv -> z20
cjd XOR qtn -> z17
fsf AND fgs -> nmb
wps AND mtn -> rpt
x33 XOR y33 -> mtn
bcq XOR hnk -> z27
tbh OR wwk -> nhg
twb XOR tsm -> z19
frt AND mhw -> wdr
y15 AND x15 -> pwr
rbw XOR dfv -> z30
vss AND vqs -> ctt
x28 AND y28 -> gjq
y28 XOR x28 -> dvf
bbc XOR jkb -> sgj
x43 XOR y43 -> fps
y04 AND x04 -> khw
pwg OR kpp -> ghr
x31 XOR y31 -> nrr
gmw XOR gck -> z07
frt XOR mhw -> z21
spb AND tng -> skq
svt AND hkg -> knf
gjn AND kdh -> bjb
qfs XOR rfv -> z34
cpc AND nbm -> jtt
tqh OR ccw -> nbm
jtt OR qkv -> wds
gds XOR ghr -> z32
rbw AND dfv -> qnv
msb AND bgd -> gjr
qnv OR bjd -> sms
y18 AND x18 -> pns
x41 XOR y41 -> rsb
x26 AND y26 -> srh
nvc OR npd -> ddh
dtm OR gjr -> ntv
x08 AND y08 -> jrf
y14 XOR x14 -> ttd
y06 AND x06 -> wvr
y16 AND x16 -> cwb
rnc OR qgn -> wrg
y30 AND x30 -> bjd
jqd XOR mhc -> z37
ddh XOR tnm -> z39
x12 AND y12 -> wgk
cqh OR fgg -> ngh
kdh XOR gjn -> z22
x01 XOR y01 -> wqc
khw OR djm -> wht
ctt OR pwr -> rgp
y21 XOR x21 -> mhw
vjp OR nwg -> dhh
x02 XOR y02 -> wmr
gck AND gmw -> pjf
rqv OR pns -> twb
y00 AND x00 -> qtf
y05 AND x05 -> njq
y29 AND x29 -> rjf
vrk AND tdw -> hsf
y42 AND x42 -> qkv
y10 XOR x10 -> bgd
cfg XOR ngh -> z26
tng XOR spb -> z06
y00 XOR x00 -> z00
cpb XOR wmr -> z02
ckd OR tdk -> wps
jrq OR srh -> hnk
y22 XOR x22 -> hjf
x03 AND y03 -> bjw
nhg XOR ttd -> vss
tsm AND twb -> rwg
dqn OR hgg -> hkg
y34 XOR x34 -> rfv
y35 AND x35 -> z35
x25 AND y25 -> cqh
y33 AND x33 -> rrn
wqc AND qtf -> djn
sgs XOR rsb -> z41
x08 XOR y08 -> gkj
rwg OR jps -> cwm
rqf AND pqn -> wbv
x37 XOR y37 -> mhc
dvf XOR dhh -> z28
kdb OR rhr -> fgs
knf OR ptg -> sgs
svt XOR hkg -> z40
y13 AND x13 -> wwk
y23 AND x23 -> tqk
fgp OR hdk -> jkb
jcw XOR wpk -> z12
y06 XOR x06 -> spb
x23 XOR y23 -> tks
y09 AND x09 -> bmn
wds XOR fps -> z43
dhh AND dvf -> dfg
mgd AND skp -> src
wrg AND nwq -> nvc
y03 XOR x03 -> vrk
y36 AND x36 -> kqk
vjr AND vbb -> djm
x44 XOR y44 -> fsf
x44 AND y44 -> mbk
kqk OR wbv -> jqd
vpd XOR mvn -> z09
y09 XOR x09 -> mvn