Skip to content

Commit 05b0a57

Browse files
committed
Solution 2017-18, part 1 (Duet)
1 parent fc0f5f0 commit 05b0a57

File tree

2 files changed

+205
-0
lines changed
  • src
    • main/kotlin/de/ronny_h/aoc/year2017/day18
    • test/kotlin/de/ronny_h/aoc/year2017/day18

2 files changed

+205
-0
lines changed
Lines changed: 157 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,157 @@
1+
package de.ronny_h.aoc.year2017.day18
2+
3+
import de.ronny_h.aoc.AdventOfCode
4+
import de.ronny_h.aoc.extensions.numbers.isInt
5+
import de.ronny_h.aoc.extensions.numbers.toIntChecked
6+
import de.ronny_h.aoc.year2017.day18.Instruction.*
7+
8+
fun main() = Duet().run(9423, 0)
9+
10+
class Duet : AdventOfCode<Long>(2017, 18) {
11+
override fun part1(input: List<String>): Long = SoundPlayer(input.parseInstructions()).run()
12+
13+
override fun part2(input: List<String>): Long {
14+
return 0
15+
}
16+
}
17+
18+
fun List<String>.parseInstructions(): List<Instruction> = map {
19+
val parameters = it.substring(4)
20+
when (it.substring(0, 3)) {
21+
"snd" -> Sound(parameters)
22+
"set" -> {
23+
val (register, value) = parameters.split(" ")
24+
SetValue(register, value.toValue())
25+
}
26+
27+
"add" -> {
28+
val (register, value) = parameters.split(" ")
29+
Add(register, value.toValue())
30+
}
31+
32+
"mul" -> {
33+
val (register, value) = parameters.split(" ")
34+
Multiply(register, value.toValue())
35+
}
36+
37+
"mod" -> {
38+
val (register, value) = parameters.split(" ")
39+
Modulo(register, value.toValue())
40+
}
41+
42+
"rcv" -> {
43+
Recover(parameters)
44+
}
45+
46+
"jgz" -> {
47+
val (register, value) = parameters.split(" ")
48+
JumpIfGreaterZero(register, value.toValue())
49+
}
50+
51+
else -> error("unknown instruction: $it")
52+
}
53+
}
54+
55+
fun String.toValue(): Value = if (isInt()) {
56+
Value.Number(toLong())
57+
} else {
58+
Value.Register(this)
59+
}
60+
61+
sealed interface Value {
62+
fun toNumber(registers: Map<String, Long>): Long
63+
64+
data class Register(private val register: String) : Value {
65+
override fun toNumber(registers: Map<String, Long>): Long = registers.getValue(register)
66+
}
67+
68+
data class Number(val value: Long) : Value {
69+
override fun toNumber(registers: Map<String, Long>): Long = value
70+
}
71+
}
72+
73+
sealed interface Instruction {
74+
fun executeOn(registers: MutableMap<String, Long>): Long
75+
76+
companion object {
77+
private const val LAST_PLAYED_SOUND_REGISTER = "lastPlayedSound"
78+
}
79+
80+
data class Sound(private val register: String) : Instruction {
81+
override fun executeOn(registers: MutableMap<String, Long>): Long {
82+
val frequency = registers.getValue(register)
83+
println("playing frequency $frequency")
84+
registers[LAST_PLAYED_SOUND_REGISTER] = frequency
85+
return frequency
86+
}
87+
}
88+
89+
data class SetValue(private val register: String, val value: Value) : Instruction {
90+
override fun executeOn(registers: MutableMap<String, Long>): Long {
91+
registers[register] = value.toNumber(registers)
92+
return registers.getValue(register)
93+
}
94+
}
95+
96+
data class Add(private val register: String, val value: Value) : Instruction {
97+
override fun executeOn(registers: MutableMap<String, Long>): Long {
98+
registers[register] = registers.getValue(register) + value.toNumber(registers)
99+
return registers.getValue(register)
100+
}
101+
}
102+
103+
data class Multiply(private val register: String, val value: Value) : Instruction {
104+
override fun executeOn(registers: MutableMap<String, Long>): Long {
105+
registers[register] = registers.getValue(register) * value.toNumber(registers)
106+
return registers.getValue(register)
107+
}
108+
}
109+
110+
data class Modulo(private val register: String, val value: Value) : Instruction {
111+
override fun executeOn(registers: MutableMap<String, Long>): Long {
112+
registers[register] = registers.getValue(register) % value.toNumber(registers)
113+
return registers.getValue(register)
114+
}
115+
}
116+
117+
data class Recover(val register: String) : Instruction {
118+
override fun executeOn(registers: MutableMap<String, Long>): Long {
119+
if (registers.getValue(register) != 0L) {
120+
val frequency = registers.getValue(LAST_PLAYED_SOUND_REGISTER)
121+
println("recover last played sound's frequency: $frequency")
122+
return frequency
123+
}
124+
return 0
125+
}
126+
}
127+
128+
data class JumpIfGreaterZero(private val register: String, val value: Value) : Instruction {
129+
override fun executeOn(registers: MutableMap<String, Long>): Long {
130+
if (registers.getValue(register) > 0) {
131+
return value.toNumber(registers)
132+
}
133+
return 1
134+
}
135+
}
136+
}
137+
138+
class SoundPlayer(private val instructions: List<Instruction>) {
139+
private val registers = mutableMapOf<String, Long>().withDefault { 0 }
140+
private var instructionPointer = 0L
141+
142+
fun run(): Long {
143+
while (instructionPointer in instructions.indices) {
144+
val instruction = instructions[instructionPointer.toIntChecked()]
145+
val result = instruction.executeOn(registers)
146+
if (instruction is Recover && registers.getValue(instruction.register) != 0L) {
147+
return result
148+
}
149+
instructionPointer += if (instruction is JumpIfGreaterZero) {
150+
result
151+
} else {
152+
1L
153+
}
154+
}
155+
return -1L
156+
}
157+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package de.ronny_h.aoc.year2017.day18
2+
3+
import de.ronny_h.aoc.extensions.asList
4+
import de.ronny_h.aoc.year2017.day18.Instruction.*
5+
import de.ronny_h.aoc.year2017.day18.Value.Number
6+
import de.ronny_h.aoc.year2017.day18.Value.Register
7+
import io.kotest.core.spec.style.StringSpec
8+
import io.kotest.matchers.shouldBe
9+
10+
class DuetTest : StringSpec({
11+
12+
val input = """
13+
set a 1
14+
add a 2
15+
mul a a
16+
mod a 5
17+
snd a
18+
set a 0
19+
rcv a
20+
jgz a -1
21+
set a 1
22+
jgz a -2
23+
""".asList()
24+
25+
"instructions can be parsed" {
26+
input.parseInstructions() shouldBe listOf(
27+
SetValue("a", Number(1)),
28+
Add("a", Number(2)),
29+
Multiply("a", Register("a")),
30+
Modulo("a", Number(5)),
31+
Sound("a"),
32+
SetValue("a", Number(0)),
33+
Recover("a"),
34+
JumpIfGreaterZero("a", Number(-1)),
35+
SetValue("a", Number(1)),
36+
JumpIfGreaterZero("a", Number(-2)),
37+
)
38+
}
39+
40+
"part 1: the value of the recovered frequency the first time a rcv instruction is executed with a non-zero value" {
41+
Duet().part1(input) shouldBe 4
42+
}
43+
44+
"part 2" {
45+
val input = listOf("")
46+
Duet().part2(input) shouldBe 0
47+
}
48+
})

0 commit comments

Comments
 (0)