Skip to content

Commit c9ebd4f

Browse files
committed
Day 17 finished
1 parent 2485650 commit c9ebd4f

File tree

5 files changed

+121
-6
lines changed

5 files changed

+121
-6
lines changed
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* Copyright (c) 2024 James Carman
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package adventofcode.day17
18+
19+
import adventofcode.util.splitByEmptyLines
20+
import adventofcode.util.splitsAs
21+
import kotlin.math.pow
22+
23+
fun Long.pow(exponent: Long) = this.toDouble().pow(exponent.toDouble()).toInt()
24+
25+
fun String.parseComputer(): Computer {
26+
val parts = splitByEmptyLines()
27+
val (a, b, c) = parts[0].lines().map { it.substringAfter(':').trim().toLong() }
28+
val program = parts[1].substringAfter(':').trim().replace(',', ' ').splitsAs { it.toLong() }
29+
return Computer(a, b, c, program)
30+
}
31+
32+
fun String.determineProgramOutput(): String {
33+
val computer = parseComputer()
34+
val output = computer.runProgram()
35+
return output.joinToString(separator = ",")
36+
}
37+
38+
fun String.findLeastSelfReplicatingValueForA() = generatorsOf(this, parseComputer().program).first()
39+
40+
private fun generatorsOf(input: String, output: List<Long>): List<Long> {
41+
if(output.size == 1) {
42+
return (0L..7L).filter { input.parseComputer().initializeARegister(it).runProgram() == output }
43+
}
44+
val tailGenerators = generatorsOf(input, output.drop(1))
45+
return tailGenerators.flatMap { generator ->
46+
(0..7).map { generator * 8 + it }
47+
.filter { input.parseComputer().initializeARegister(it).runProgram() == output }
48+
}
49+
}
50+
51+
class Computer(
52+
private var a: Long = 0,
53+
private var b: Long = 0,
54+
private var c: Long = 0,
55+
val program: List<Long>
56+
) {
57+
private var instructionPoInter: Int = 0
58+
59+
fun initializeARegister(value: Long): Computer {
60+
a = value
61+
return this
62+
}
63+
64+
private fun operand() = program[instructionPoInter + 1]
65+
66+
private fun literal(): Long = operand()
67+
68+
private fun combo(): Long = when (operand()) {
69+
4L -> a
70+
5L -> b
71+
6L -> c
72+
else -> literal()
73+
}
74+
75+
fun runProgram(): List<Long> {
76+
val output = mutableListOf<Long>()
77+
while (instructionPoInter < program.size) {
78+
val currentInstructionPoInter = instructionPoInter
79+
when (program[instructionPoInter]) {
80+
0L -> a = a / 2L.pow(combo())
81+
1L -> b = b xor literal()
82+
2L -> b = combo() % 8
83+
3L -> if (a != 0L) instructionPoInter = literal().toInt()
84+
4L -> b = b xor c
85+
5L -> output += combo() % 8
86+
6L -> b = a / 2L.pow(combo())
87+
7L -> c = a / 2L.pow(combo())
88+
else -> throw IllegalArgumentException("Unknown opcode: $program[$instructionPoInter]")
89+
}
90+
if (currentInstructionPoInter == instructionPoInter) {
91+
instructionPoInter += 2
92+
}
93+
}
94+
return output
95+
}
96+
97+
}

src/test/kotlin/adventofcode/Day17Test.kt

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,32 +16,35 @@
1616

1717
package adventofcode
1818

19+
20+
import adventofcode.day17.determineProgramOutput
21+
import adventofcode.day17.findLeastSelfReplicatingValueForA
1922
import io.kotest.matchers.shouldBe
2023
import org.junit.jupiter.api.Test
2124

2225
class Day17Test {
2326

2427
@Test
2528
fun example1() {
26-
calculatePart1(readExample1()) shouldBe 0
29+
calculatePart1(readExample1()) shouldBe "4,6,3,5,6,3,5,2,1,0"
2730
}
2831

2932
@Test
3033
fun part1() {
31-
calculatePart1(readInput()) shouldBe 0
34+
calculatePart1(readInput()) shouldBe "7,3,5,7,5,7,4,3,0"
3235
}
3336

3437
@Test
3538
fun example2() {
36-
calculatePart2(readExample2()) shouldBe 0
39+
calculatePart2(readExample2()) shouldBe 117440L
3740
}
3841

3942
@Test
4043
fun part2() {
41-
calculatePart2(readInput()) shouldBe 0
44+
calculatePart2(readInput()) shouldBe 105734774294938L
4245
}
4346

44-
private fun calculatePart1(input: String): Int = 0
47+
private fun calculatePart1(input: String): String = input.determineProgramOutput()
4548

46-
private fun calculatePart2(input: String): Int = 0
49+
private fun calculatePart2(input: String): Long = input.findLeastSelfReplicatingValueForA()
4750
}

src/test/resources/day17-example1.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 729
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 0,1,5,4,3,0

src/test/resources/day17-example2.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 2024
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 0,3,5,4,3,0

src/test/resources/day17.txt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
Register A: 61156655
2+
Register B: 0
3+
Register C: 0
4+
5+
Program: 2,4,1,5,7,5,4,3,1,6,0,3,5,5,3,0

0 commit comments

Comments
 (0)