Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 77a38e1

Browse files
committedDec 17, 2024
feat(2024/17): part 1
1 parent b0d3ae3 commit 77a38e1

File tree

2 files changed

+128
-0
lines changed

2 files changed

+128
-0
lines changed
 

‎2024/day17.scala

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
package `2024`.day17
2+
3+
import prelude.*
4+
import scala.collection.immutable.Queue
5+
6+
enum Code:
7+
case Adv, Bxl, Bst, Jnz, Bxc, Out, Bdv, Cdv
8+
object Code:
9+
val ops = Vector(Adv, Bxl, Bst, Jnz, Bxc, Out, Bdv, Cdv)
10+
def parse(c: Int): Code = ops(c)
11+
12+
enum Reg(val v: Int):
13+
case A extends Reg(0)
14+
case B extends Reg(1)
15+
case C extends Reg(2)
16+
17+
case class Regs(regs: Vector[Int]):
18+
def apply(r: Reg): Int = regs(r.v)
19+
def update(r: Reg, v: Int): Regs = Regs(regs.updated(r.v, v))
20+
object Regs:
21+
def apply(regs: Int*) = new Regs(regs.toVector)
22+
23+
case class Computer(
24+
regs: Regs = Regs(0, 0, 0),
25+
inst: Vector[(Code, Int)],
26+
output: Queue[Int] = Queue.empty,
27+
ptr: Int = 0,
28+
):
29+
extension (r: Reg)
30+
def <--(v: Int) = copy(regs = (regs(r) = v), ptr = ptr + 1)
31+
def get: Int = regs(r)
32+
33+
extension (op: Int)
34+
def combo: Int = op match
35+
case 4 => Reg.A.get
36+
case 5 => Reg.B.get
37+
case 6 => Reg.C.get
38+
case 7 => ???
39+
case _ => op
40+
def div = Reg.A.get / (2 ** op.combo)
41+
def modulo = op.combo & 0b111
42+
43+
def unfold: Iterator[Computer] =
44+
Iterator.unfold(this)(_.next.map(x => (x, x)))
45+
def run: Computer = unfold.foldLeft(this)((_, current) => current)
46+
47+
def next: Option[Computer] =
48+
inst.lift(ptr).map { (code, op) => next(code, op) }
49+
50+
def next(code: Code, op: Int): Computer = code match
51+
case Code.Adv => Reg.A <-- op.div
52+
case Code.Bdv => Reg.B <-- op.div
53+
case Code.Cdv => Reg.C <-- op.div
54+
case Code.Bxl => Reg.B <-- (Reg.B.get ^ op)
55+
case Code.Bst => Reg.B <-- op.modulo
56+
case Code.Bxc => Reg.B <-- (Reg.B.get ^ Reg.C.get)
57+
case Code.Jnz => copy(ptr = if Reg.A.get == 0 then ptr + 1 else op)
58+
case Code.Out => copy(output = output :+ op.modulo, ptr = ptr + 1)
59+
60+
def pretty = s"""
61+
${ptr.toString.padTo(3, ' ')} @ ${regs.regs
62+
.map(x => s"${x.toBinaryString} ($x)")
63+
.mkString(", ")}
64+
$output >>
65+
$inst
66+
""".dedent
67+
68+
object Computer:
69+
def parse(input: String): Computer = input match
70+
case s"""Register A: ${I(a)}
71+
Register B: ${I(b)}
72+
Register C: ${I(c)}
73+
74+
Program: $xs""" => Computer(Regs(a, b, c), `2024`.day17.parse(xs))
75+
76+
def parse(input: String): Vector[(Code, Int)] = input
77+
.split(",")
78+
.map(_.toInt)
79+
.grouped(2)
80+
.collect { case Array(c, o) => (Code.parse(c), o) }
81+
.toVector
82+
83+
@main def main() =
84+
val input = readInput(this).mkString.trim
85+
val c = Computer.parse(input)
86+
println(c.pretty)
87+
val res = c.run
88+
println(res.pretty)
89+
res.output.mkString(",") |> println

‎2024/day17.test.scala

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package `2024`.day17
2+
3+
import munit.FunSuite
4+
import scala.collection.immutable.Queue
5+
import prelude.dedent
6+
7+
class ComputerTest extends FunSuite:
8+
test("{C:9} <- 2,6"):
9+
val c = Computer(Regs(0, 0, 9), parse("2,6"))
10+
assertEquals(c.next.map(_.regs), Some(Regs(0, 1, 9)))
11+
12+
test("{A:10} <- 5,0,5,1,5,4"):
13+
val c = Computer(Regs(10, 0, 0), parse("5,0,5,1,5,4"))
14+
assertEquals(c.run.output, Queue(0, 1, 2))
15+
16+
test("{A:2024} <- 0,1,5,4,3,0"):
17+
val c = Computer(Regs(2024, 0, 0), parse("0,1,5,4,3,0"))
18+
val after = c.run
19+
assertEquals(after.output, Queue(4, 2, 5, 6, 7, 7, 7, 7, 3, 1, 0))
20+
assertEquals(after.regs, Regs(0, 0, 0))
21+
22+
test("{B:29} <- 1,7"):
23+
val c = Computer(Regs(0, 29, 0), parse("1,7"))
24+
assertEquals(c.run.regs, Regs(0, 26, 0))
25+
26+
test("{B:2024, C:43690} <- 4,0"):
27+
val c = Computer(Regs(0, 2024, 43690), parse("4,0"))
28+
assertEquals(c.run.regs, Regs(0, 44354, 43690))
29+
30+
test("example"):
31+
val example = """
32+
Register A: 729
33+
Register B: 0
34+
Register C: 0
35+
36+
Program: 0,1,5,4,3,0
37+
""".dedent
38+
val c = Computer.parse(example)
39+
assertEquals(c.run.output.mkString(","), "4,6,3,5,6,3,5,2,1,0")

0 commit comments

Comments
 (0)
Failed to load comments.