From 895395130f239b7ec43712c3ff174d7dc4b7201b Mon Sep 17 00:00:00 2001 From: scarf Date: Tue, 17 Dec 2024 22:24:15 +0900 Subject: [PATCH] feat(2024/17): part 1 --- 2024/day17.scala | 116 ++++++++++++++++++++++++++++++++++++++++++ 2024/day17.test.scala | 39 ++++++++++++++ 2 files changed, 155 insertions(+) create mode 100644 2024/day17.scala create mode 100644 2024/day17.test.scala diff --git a/2024/day17.scala b/2024/day17.scala new file mode 100644 index 0000000..fb3c038 --- /dev/null +++ b/2024/day17.scala @@ -0,0 +1,116 @@ +package `2024`.day17 + +import prelude.* +import scala.collection.immutable.Queue + +enum Code: + case Adv, Bxl, Bst, Jnz, Bxc, Out, Bdv, Cdv +object Code: + val ops = Vector(Adv, Bxl, Bst, Jnz, Bxc, Out, Bdv, Cdv) + def parse(c: Int): Code = ops(c) + +enum Op(val lit: Int): + case Literal(v: Int) extends Op(v) + case Register(r: Reg) extends Op(r.v + 4) + case Reserved(v: Int) extends Op(v) + + override def toString = this match + case Literal(v) => s"$v" + case Register(r) => s"$r" + case Reserved(_) => "??" +object Op: + def parse(c: Int): Op = c match + case 4 => Register(Reg.A) + case 5 => Register(Reg.B) + case 6 => Register(Reg.C) + case 7 => Reserved(c) + case _ => Literal(c) + +case class Inst(code: Code, op: Op) + +enum Reg(val v: Int): + case A extends Reg(0) + case B extends Reg(1) + case C extends Reg(2) + +case class Regs(regs: Vector[Int]): + def apply(r: Reg): Int = regs(r.v) + def update(r: Reg, v: Int): Regs = Regs(regs.updated(r.v, v)) +object Regs: + def apply(regs: Int*) = new Regs(regs.toVector) + +case class Computer( + regs: Regs = Regs(0, 0, 0), + inst: Vector[Inst], + output: Queue[Int] = Queue.empty, + ptr: Int = 0, +): + extension (r: Reg) + def <--(v: Int) = copy(regs = (regs(r) = v), ptr = ptr + 1) + def get: Int = regs(r) + + extension (op: Op) + def combo: Int = op match + case Op.Literal(v) => v + case Op.Register(r) => r.get + case _ => ??? + def div = Reg.A.get / (2 ** op.combo) + def modulo = op.combo % 8 + + def unfold: Iterator[Computer] = + Iterator.unfold(this)(_.next.map(x => (x, x))) + def run: Computer = unfold.foldLeft(this)((_, current) => current) + + def next: Option[Computer] = + inst.lift(ptr).map { case Inst(code, op) => next(code, op) } + + def next(code: Code, op: Op): Computer = code match + case Code.Adv => Reg.A <-- op.div + case Code.Bdv => Reg.B <-- op.div + case Code.Cdv => Reg.C <-- op.div + case Code.Bxl => Reg.B <-- (Reg.B.get ^ op.lit) + case Code.Bst => Reg.B <-- op.modulo + case Code.Bxc => Reg.B <-- (Reg.B.get ^ Reg.C.get) + case Code.Jnz => copy(ptr = if Reg.A.get == 0 then ptr + 1 else op.lit) + case Code.Out => copy(output = output :+ op.modulo, ptr = ptr + 1) + + def pretty = s""" + ${ptr.toString.padTo(4, ' ')} @ ${regs.regs.mkString("{", ",", "}")} + $output >> + $inst + """.dedent + +object Computer: + def parse(input: String): Computer = input match + case s"""Register A: ${I(a)} +Register B: ${I(b)} +Register C: ${I(c)} + +Program: $xs""" => Computer(Regs(a, b, c), `2024`.day17.parse(xs)) + +def parse(input: String): Vector[Inst] = input + .split(",") + .map(_.toInt) + .grouped(2) + .collect { case Array(c, o) => Inst(Code.parse(c), Op.parse(o)) } + .toVector + +val example = """ +Register A: 729 +Register B: 0 +Register C: 0 + +Program: 0,1,5,4,3,0 +""".dedent + +@main def main() = + val input = readInput(this).mkString.trim + // val computer = Computer(Regs(0, 0, 9), parse("2,6")) + // println(computer.pretty) + // println(computer.run.pretty) + val c = Computer.parse(input) + // val c = Computer(Regs(2024, 0, 0), parse("0,1,5,4,3,0")) + println(c) + val res = c.run + println(res) + res.output.mkString(",") |> println diff --git a/2024/day17.test.scala b/2024/day17.test.scala new file mode 100644 index 0000000..05007bd --- /dev/null +++ b/2024/day17.test.scala @@ -0,0 +1,39 @@ +package `2024`.day17 + +import munit.FunSuite +import scala.collection.immutable.Queue +import prelude.dedent + +class ComputerTest extends FunSuite: + test("{C:9} <- 2,6"): + val c = Computer(Regs(0, 0, 9), parse("2,6")) + assertEquals(c.next.map(_.regs), Some(Regs(0, 1, 9))) + + test("{A:10} <- 5,0,5,1,5,4"): + val c = Computer(Regs(10, 0, 0), parse("5,0,5,1,5,4")) + assertEquals(c.run.output, Queue(0, 1, 2)) + + test("{A:2024} <- 0,1,5,4,3,0"): + val c = Computer(Regs(2024, 0, 0), parse("0,1,5,4,3,0")) + val after = c.run + assertEquals(after.output, Queue(4, 2, 5, 6, 7, 7, 7, 7, 3, 1, 0)) + assertEquals(after.regs, Regs(0, 0, 0)) + + test("{B:29} <- 1,7"): + val c = Computer(Regs(0, 29, 0), parse("1,7")) + assertEquals(c.run.regs, Regs(0, 26, 0)) + + test("{B:2024, C:43690} <- 4,0"): + val c = Computer(Regs(0, 2024, 43690), parse("4,0")) + assertEquals(c.run.regs, Regs(0, 44354, 43690)) + + test("example"): + val example = """ + Register A: 729 + Register B: 0 + Register C: 0 + + Program: 0,1,5,4,3,0 + """.dedent + val c = Computer.parse(example) + assertEquals(c.run.output.mkString(","), "4,6,3,5,6,3,5,2,1,0")