Skip to content

Commit 18a01f1

Browse files
committed
2016.23
1 parent 8dba93a commit 18a01f1

File tree

3 files changed

+186
-0
lines changed

3 files changed

+186
-0
lines changed

src/main/resources/y2016/day23.txt

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
cpy a b
2+
dec b
3+
cpy a d
4+
cpy 0 a
5+
cpy b c
6+
inc a
7+
dec c
8+
jnz c -2
9+
dec d
10+
jnz d -5
11+
dec b
12+
cpy b c
13+
cpy c d
14+
dec d
15+
inc c
16+
jnz d -2
17+
tgl c
18+
cpy -16 c
19+
jnz 1 c
20+
cpy 99 c
21+
jnz 77 d
22+
inc a
23+
inc d
24+
jnz d -2
25+
inc c
26+
jnz c -5

src/main/scala/y2016/Day23.scala

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
package y2016
2+
3+
import scala.annotation.tailrec
4+
import scala.collection.mutable
5+
import scala.util.matching.Regex
6+
import scala.util.Try
7+
import scala.util.parsing.combinator.RegexParsers
8+
9+
trait Day23 {
10+
11+
12+
object Machine {
13+
val step = 3
14+
val toReg = Array("a", "b", "c", "d")
15+
16+
def compile(code: Seq[String], a: Int): Machine = new Machine(Compiler.compile(code), mutable.Map("a" -> a).withDefaultValue(0))
17+
}
18+
19+
class Machine(code: Array[Byte], val registers: mutable.Map[String, Int]) {
20+
21+
import Machine._
22+
import Compiler.OpCode._
23+
24+
var cursor = 0
25+
26+
def load(c: Int): Int =
27+
if code(c) >= 100 then
28+
registers(s"${(code(c) - 100 + 'a').toChar}")
29+
else code(c).toInt
30+
31+
def reg(c: Int): Option[String] =
32+
if code(c) >= 100 then
33+
Some(toReg(code(c) - 100))
34+
else None
35+
36+
def hasNext(): Boolean =
37+
cursor <= code.length - step
38+
39+
def next(): Unit = {
40+
// println(this)
41+
code(cursor) match {
42+
case CPY.code =>
43+
reg(cursor + 2).map(name => registers(name) = load(cursor + 1)).getOrElse(sys.error(""))
44+
cursor += step
45+
case INC.code =>
46+
reg(cursor + 1).map(name => registers(name) += 1).getOrElse(sys.error(""))
47+
cursor += step
48+
case DEC.code =>
49+
reg(cursor + 1).map(name => registers(name) -= 1).getOrElse(sys.error(""))
50+
cursor += step
51+
case JNZ.code =>
52+
if load(cursor + 1) == 0 then cursor += step
53+
else cursor += load(cursor + 2) * step
54+
case TGL.code =>
55+
val delta = cursor + load(cursor + 1) * step
56+
Try {
57+
code(delta) match {
58+
case CPY.code => code(delta) = JNZ.code
59+
case INC.code => code(delta) = DEC.code
60+
case DEC.code => code(delta) = INC.code
61+
case JNZ.code => code(delta) = CPY.code
62+
case TGL.code => code(delta) = INC.code
63+
}
64+
}
65+
cursor += step
66+
}
67+
}
68+
69+
override def toString: String = s"Machine\n registers=$registers\n cursor=$cursor\n${decompile()}"
70+
71+
def decompile(): String = {
72+
def pretty(b: Byte): String = if b >= 100 then s"${(b - 100 + 'a').toChar}" else s"${b.toInt}"
73+
74+
val sb = new StringBuilder
75+
76+
@tailrec def recurse(i: Int): Unit = {
77+
if i == cursor then sb.append("*") else sb.append(" ")
78+
if (i >= code.length - step) ()
79+
else
80+
val (r1, r2) = (pretty(code(i + 1)), pretty(code(i + 2)))
81+
code(i) match {
82+
case CPY.code => sb.append(s"cpy $r1 $r2\n")
83+
case INC.code => sb.append(s"inc $r1\n")
84+
case DEC.code => sb.append(s"dec $r1\n")
85+
case JNZ.code => sb.append(s"jnz $r1 $r2\n")
86+
case TGL.code => sb.append(s"tgl $r1\n")
87+
}
88+
recurse(i + step)
89+
}
90+
91+
recurse(0)
92+
sb.toString()
93+
}
94+
}
95+
96+
def solve1(input: Seq[String], a: Int): Int = {
97+
val machine = Machine.compile(input, a)
98+
println(machine)
99+
println("-" * 80)
100+
while (machine.hasNext()) machine.next()
101+
println(machine)
102+
machine.registers("a")
103+
}
104+
105+
object Compiler extends RegexParsers {
106+
enum OpCode(val code: Byte):
107+
case CPY extends OpCode(1)
108+
case INC extends OpCode(2)
109+
case DEC extends OpCode(3)
110+
case JNZ extends OpCode(4)
111+
case TGL extends OpCode(5)
112+
113+
import OpCode._
114+
115+
def addressToByte(str: String): Byte = if str.head.isLetter then (str.head - 'a' + 100).toByte else str.toByte
116+
117+
def address: Parser[Byte] = """-?\w+""".r ^^ addressToByte
118+
119+
def cpy: Parser[Array[Byte]] = "cpy" ~> address ~ address ^^ {
120+
case src ~ dest => Array[Byte](CPY.code, src, dest)
121+
}
122+
123+
def inc: Parser[Array[Byte]] = "inc" ~> address ^^ {
124+
dest => Array(INC.code, dest, 0)
125+
}
126+
127+
def dec: Parser[Array[Byte]] = "dec" ~> address ^^ {
128+
dest => Array(DEC.code, dest, 0)
129+
}
130+
131+
def jnz: Parser[Array[Byte]] = "jnz" ~> address ~ address ^^ {
132+
case src ~ dest => Array[Byte](JNZ.code, src, dest)
133+
}
134+
135+
def tgl: Parser[Array[Byte]] = "tgl" ~> address ^^ {
136+
dest => Array[Byte](TGL.code, dest, 0)
137+
}
138+
139+
def codeParser: Parser[Array[Byte]] = inc | dec | cpy | jnz | tgl
140+
141+
def compile(code: Seq[String]): Array[Byte] = {
142+
code.foldLeft(Array[Byte]()) {
143+
case (compiled, line) => compiled ++ parseAll(codeParser, line).get
144+
}
145+
}
146+
}
147+
}

src/test/scala/y2016/Day23Spec.scala

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package y2016
2+
3+
import org.scalatest.flatspec.AnyFlatSpec
4+
import org.scalatest.matchers.should.*
5+
6+
class Day23Spec extends AnyFlatSpec with Matchers with Day23 {
7+
lazy val input: Seq[String] = util.Loader(this, "day23.txt").toSeq
8+
9+
it should "solve" in {
10+
solve1(input, 7) shouldBe 12663
11+
solve1(input, 12) shouldBe 479009223
12+
}
13+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy