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 4dd9b6b
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 0 deletions.
90 changes: 90 additions & 0 deletions 2024/day17.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
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 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[(Code, Int)],
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: Int)
def combo: Int = op match
case 4 => Reg.A.get
case 5 => Reg.B.get
case 6 => Reg.C.get
case 7 => ???
case _ => op
def div = Reg.A.get / (2 ** op.combo)
def modulo = op.combo & 0b111

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 { (code, op) => next(code, op) }

def next(code: Code, op: Int): 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)
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)
case Code.Out => copy(output = output :+ op.modulo, ptr = ptr + 1)

def pretty = s"""
${ptr.toString.padTo(3, ' ')} @ ${regs.regs
.map(x => s"${x.toBinaryString} ($x)")
.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[(Code, Int)] = input
.split(",")
.map(_.toInt)
.grouped(2)
.collect { case Array(c, o) => (Code.parse(c), o) }
.toVector

@main def main() =
val input = readInput(this).mkString.trim
val c = Computer.parse(input)
println(c.pretty)
val res = c.run
println(res.pretty)
res.output.mkString(",") |> println
println(parse("0,3,5,4,3,0"))
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 4dd9b6b

Please sign in to comment.