Skip to content

Commit

Permalink
feat(2024/17): part 1
Browse files Browse the repository at this point in the history
  • Loading branch information
scarf005 committed Dec 17, 2024
1 parent 64f1588 commit 8953951
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 0 deletions.
116 changes: 116 additions & 0 deletions 2024/day17.scala
Original file line number Diff line number Diff line change
@@ -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
39 changes: 39 additions & 0 deletions 2024/day17.test.scala
Original file line number Diff line number Diff line change
@@ -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")

0 comments on commit 8953951

Please sign in to comment.