Compare commits

...

6 Commits

Author SHA1 Message Date
Christian
1d9dc696a8 Day 16: Early exit search loop 2025-01-24 22:52:32 +01:00
Christian
9654c59bfd Day 16: Use two stacks instead of PQ 2025-01-24 17:24:56 +01:00
Christian
65b220007e Eternal builds 2024-12-28 22:45:09 +01:00
Christian
3515ad8d11 Day 24.... cleanup 2024-12-28 14:19:44 +01:00
Christian
76367959ae Day 24 ... overfit 2024-12-28 14:15:13 +01:00
Christian
3c6824e070 Day 25 2024-12-25 08:35:30 +01:00
10 changed files with 4474 additions and 19 deletions

View File

@@ -4,8 +4,8 @@ language: "scala"
dockerfile: "Dockerfile"
code: "/code"
workdir: "/code"
runonce: "./mill aoc.assembly"
cmd: "java -jar ./out/aoc/assembly.dest/out.jar %day% %input%"
runonce: "./mill aoc.nativeImage"
cmd: "./out/aoc/nativeImage.dest/aoc %day% %input%"
environment:
- AOC_BENCH=1
daypath: "aoc/src/dev/ctsk/aoc/days/Day%dayzero%.scala"

View File

@@ -1,9 +1,15 @@
FROM eclipse-temurin:23-jdk-alpine
FROM eclipse-temurin:23-jdk
RUN apk add curl
RUN apt-get update && apt-get install -y curl gzip build-essential libz-dev
RUN curl -fL "https://github.com/coursier/launchers/raw/master/cs-x86_64-pc-linux.gz" | gzip -d > cs
RUN chmod +x cs
RUN cp cs /usr/local/bin
RUN ./cs setup --yes
COPY . /build
WORKDIR /build
RUN ./mill aoc.assembly
RUN ./mill aoc.nativeImage

View File

@@ -25,7 +25,9 @@ val solvers = Map[Int, Solver](
20 -> Day20,
21 -> Day21,
22 -> Day22,
23 -> Day23
23 -> Day23,
24 -> Day24,
25 -> Day25
)
def runSolver(solver: Solver, input: os.Path): Unit =
@@ -36,7 +38,9 @@ def runSolver(solver: Solver, input: os.Path): Unit =
println(solution.p2)
case None =>
println(f"=============================================================")
println(f"Day ${solver.day}%02d ------------------------------------------------------")
println(
f"Day ${solver.day}%02d ------------------------------------------------------"
)
println(f"Prep ${timings.prep}%53s μs")
println(f"Part 1 ${solution.p1}%40s ${timings.p1}%10s μs")
println(f"Part 2 ${solution.p2}%40s ${timings.p2}%10s μs")

View File

@@ -3,6 +3,8 @@ package dev.ctsk.aoc.days
import dev.ctsk.aoc.{Direction, *}
import scala.collection.mutable
import scala.util.boundary
import scala.util.boundary.break
object Day16 extends Solver(16):
override def run(input_ : os.ReadablePath): (Timings, Solution) =
@@ -14,28 +16,40 @@ object Day16 extends Solver(16):
val end = grid.findFirst(_ == 'E').get
case class State(distance: Int, pose: Pose)
implicit def ord: Ordering[State] = Ordering.by(-1 * _.distance)
Direction.Up.ordinal
def search(start: Pose): (Map[Pose, Int], Map[Pose, List[Pose]]) =
val distance = mutable.Map(start -> 0)
val ancestor = mutable.Map.empty[Pose, List[Pose]]
val heap = mutable.PriorityQueue(State(0, start))
var near = mutable.Stack(State(0, start))
var far = mutable.Stack.empty[State]
inline def relax(u: Pose, v: Pose, vDist: Int): Unit =
inline def relax(u: Pose, v: Pose, vDist: Int, isFar: Boolean): Unit =
val oldDist = distance.getOrElse(v, 1_000_000)
if vDist == oldDist then ancestor(v) +:= u
if vDist < oldDist then
ancestor(v) = List(u)
distance(v) = vDist
heap.enqueue(State(vDist, v))
if isFar
then far.push(State(vDist, v))
else near.push(State(vDist, v))
while heap.nonEmpty do
val State(uDist, u) = heap.dequeue()
boundary:
while near.nonEmpty do
var atEnd = false;
while near.nonEmpty do
val State(uDist, u) = near.pop()
atEnd |= u.pos == end
if uDist == distance(u) then
if !grid(u.step.pos).contains('#') then relax(u, u.step, uDist + 1)
for (v <- Seq(u.turnLeft, u.turnRight)) do relax(u, v, uDist + 1000)
if !grid(u.step.pos).contains('#') then
relax(u, u.step, uDist + 1, false)
for (v <- Seq(u.turnLeft, u.turnRight)) do
relax(u, v, uDist + 1000, true)
if atEnd then break()
val tmp = near
near = far
far = tmp
(distance.toMap, ancestor.toMap)
@@ -43,7 +57,7 @@ object Day16 extends Solver(16):
search(Pose(start, Direction.Right))
}
val endPose = DIRS.map(Pose(end, _)).minBy(distance(_))
val endPose = DIRS.map(Pose(end, _)).minBy(distance.getOrElse(_, 1_000_000))
val p1 = distance(endPose)

View File

@@ -0,0 +1,81 @@
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
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)
)

View File

@@ -0,0 +1,35 @@
package dev.ctsk.aoc.days
import dev.ctsk.aoc.*
import collection.parallel.CollectionConverters.*
object Day25 extends Solver(25):
override def run(input: os.ReadablePath): (Timings, Solution) =
val (pre_time, (locks, keys)) = timed {
os
.read(input)
.split("\n\n")
.map(_.linesIterator.map(_.toArray).toArray.transpose)
.partition(_(0)(0) == '#')
}
def profile(lock: Array[Array[Char]]): (Array[Int], Int) =
(lock.map(_.count(_ == '#')), lock.head.length)
def fits(size: Int, lock: Array[Int], key: Array[Int]): Boolean =
lock.zip(key).forall((l, k) => l + k <= size)
def p1 = timed {
val keyProfiles = keys.map(profile)
locks
.map(profile)
.map((lock, size) =>
keyProfiles.count((key, _) => fits(size, lock, key))
)
.sum
}
(
Timings(pre_time, p1._1, 0),
Solution(Int.box(p1._2), "MERRY CHRISTMAS")
)

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

1
data/25.ans Normal file
View File

@@ -0,0 +1 @@
3395

3999
data/25.in Normal file

File diff suppressed because it is too large Load Diff