Compare commits

...

4 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
4 changed files with 38 additions and 184 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

@@ -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

@@ -59,7 +59,6 @@ object Day24 extends Solver(24):
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
@@ -80,168 +79,3 @@ object Day24 extends Solver(24):
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