Day 13, that was really cool!
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
package com.basdado.adventofcode
|
||||
|
||||
import java.lang.UnsupportedOperationException
|
||||
|
||||
val FULL_OPCODES = mapOf(
|
||||
Pair(1L, OpCode(1L, 3, ::add)),
|
||||
Pair(2L, OpCode(2L, 3, ::multiply)),
|
||||
@@ -14,17 +16,39 @@ val FULL_OPCODES = mapOf(
|
||||
|
||||
|
||||
fun loadProgram(inputPath: String, opCodes: Map<Long, OpCode>, input: LongArray): IntCodeProgram {
|
||||
return IntCodeProgram(loadProgramData(inputPath), input, opCodes)
|
||||
return IntCodeProgram(loadProgramData(inputPath), StackBasedInputProvider(input), opCodes)
|
||||
}
|
||||
|
||||
fun loadProgramData(inputPath: String): LongArray {
|
||||
return line(inputPath).split(",").map { it.toLong() }.toLongArray()
|
||||
}
|
||||
|
||||
class IntCodeProgram(val data: LongArray, var inputs: LongArray, val opCodes: Map<Long, OpCode> = FULL_OPCODES,
|
||||
var pointer: Int = 0) {
|
||||
interface InputProvider {
|
||||
fun getInput(): Long
|
||||
}
|
||||
|
||||
class StackBasedInputProvider(var inputs: LongArray = longArrayOf()): InputProvider {
|
||||
|
||||
private var inputPointer: Int = 0
|
||||
|
||||
fun pushInput(input: Long) {
|
||||
inputs += input
|
||||
}
|
||||
|
||||
override fun getInput(): Long {
|
||||
return inputs[inputPointer++]
|
||||
}
|
||||
}
|
||||
|
||||
class NullInputProvider: InputProvider {
|
||||
override fun getInput(): Long {
|
||||
throw UnsupportedOperationException("This program doesn't expect any inputs")
|
||||
}
|
||||
}
|
||||
|
||||
class IntCodeProgram(val data: LongArray, private val inputProvider: InputProvider = NullInputProvider(), val opCodes: Map<Long, OpCode> = FULL_OPCODES,
|
||||
var pointer: Int = 0) {
|
||||
|
||||
var relativeBase: Long = 0
|
||||
private val outputs = mutableListOf<Long>()
|
||||
var done = false
|
||||
@@ -50,12 +74,9 @@ class IntCodeProgram(val data: LongArray, var inputs: LongArray, val opCodes: Ma
|
||||
}
|
||||
|
||||
fun getNextInput(): Long {
|
||||
return inputs[inputPointer++]
|
||||
return inputProvider.getInput()
|
||||
}
|
||||
|
||||
fun pushInput(input: Long) {
|
||||
inputs += input
|
||||
}
|
||||
fun getOutputs(): List<Long> {
|
||||
return outputs
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.basdado.adventofcode.day11
|
||||
|
||||
import com.basdado.adventofcode.IntCodeProgram
|
||||
import com.basdado.adventofcode.StackBasedInputProvider
|
||||
import com.basdado.adventofcode.loadProgramData
|
||||
|
||||
const val DAY11_INPUT_PATH = "/day/11/input.txt"
|
||||
@@ -14,9 +15,10 @@ object Day11 {
|
||||
|
||||
fun puzzle1() {
|
||||
val programData = loadProgramData(DAY11_INPUT_PATH)
|
||||
val program = IntCodeProgram(programData + LongArray(16384), longArrayOf())
|
||||
val inputProvider = StackBasedInputProvider()
|
||||
val program = IntCodeProgram(programData + LongArray(16384), inputProvider)
|
||||
val hull = mutableMapOf<Vector2i, Int>()
|
||||
paintHull(hull, program)
|
||||
paintHull(hull, program, inputProvider)
|
||||
printHull(hull)
|
||||
println(hull.size)
|
||||
}
|
||||
@@ -24,12 +26,13 @@ object Day11 {
|
||||
fun puzzle2() {
|
||||
|
||||
val programData = loadProgramData(DAY11_INPUT_PATH)
|
||||
val program = IntCodeProgram(programData + LongArray(16384), longArrayOf())
|
||||
val inputProvider = StackBasedInputProvider()
|
||||
val program = IntCodeProgram(programData + LongArray(16384), inputProvider)
|
||||
val hull = mutableMapOf<Vector2i, Int>(
|
||||
// Paint position 0,0 white
|
||||
Pair(Vector2i(0, 0), 1)
|
||||
)
|
||||
paintHull(hull, program)
|
||||
paintHull(hull, program, inputProvider)
|
||||
printHull(hull)
|
||||
}
|
||||
|
||||
@@ -59,7 +62,8 @@ object Day11 {
|
||||
|
||||
private fun paintHull(
|
||||
hull: MutableMap<Vector2i, Int>,
|
||||
program: IntCodeProgram
|
||||
program: IntCodeProgram,
|
||||
inputProvider: StackBasedInputProvider
|
||||
) {
|
||||
var pos = Vector2i(0, 0)
|
||||
var dir = UP
|
||||
@@ -69,7 +73,7 @@ object Day11 {
|
||||
while (hullPaintingSizeConstant < 1000) {
|
||||
lastHullPaintingSize = hull.size
|
||||
|
||||
program.pushInput((hull[pos] ?: 0).toLong())
|
||||
inputProvider.pushInput((hull[pos] ?: 0).toLong())
|
||||
val color = program.executeUntilOutput() ?: break
|
||||
hull[pos] = color.toInt()
|
||||
|
||||
|
||||
137
src/main/kotlin/com/basdado/adventofcode/day13/Day13.kt
Normal file
137
src/main/kotlin/com/basdado/adventofcode/day13/Day13.kt
Normal file
@@ -0,0 +1,137 @@
|
||||
package com.basdado.adventofcode.day13
|
||||
|
||||
import com.basdado.adventofcode.InputProvider
|
||||
import com.basdado.adventofcode.IntCodeProgram
|
||||
import com.basdado.adventofcode.day11.Day11
|
||||
import com.basdado.adventofcode.loadProgramData
|
||||
|
||||
const val DAY13_INPUT_PATH = "/day/13/input.txt"
|
||||
|
||||
fun main() {
|
||||
Day13.puzzle1()
|
||||
Day13.puzzle2()
|
||||
}
|
||||
|
||||
object Day13 {
|
||||
fun puzzle1() {
|
||||
|
||||
val programData = loadProgramData(DAY13_INPUT_PATH)
|
||||
val program = IntCodeProgram(programData + LongArray(16384))
|
||||
|
||||
program.execute()
|
||||
val outputs = program.getOutputs()
|
||||
|
||||
println((outputs.indices step 3).count { i -> parseTile(outputs[i + 2]) == Tile.BLOCK })
|
||||
}
|
||||
|
||||
fun puzzle2() {
|
||||
|
||||
val programData = loadProgramData(DAY13_INPUT_PATH)
|
||||
|
||||
// Play for free by setting the credits to "2"
|
||||
programData[0] = 2
|
||||
|
||||
val display = Display(0, Array<Array<Tile>>(100) { Array<Tile>(100) {Tile.EMPTY} })
|
||||
val program = IntCodeProgram(programData + LongArray(16384),
|
||||
|
||||
// Toggle the two lines below to switch between manual input or AI playing
|
||||
AIInputProvider(display))
|
||||
// JoystickInputProvider())
|
||||
|
||||
while(true) {
|
||||
val x = program.executeUntilOutput()?.toInt() ?: break
|
||||
val y = program.executeUntilOutput()!!.toInt()
|
||||
if (x == -1 && y == 0) {
|
||||
display.score = program.executeUntilOutput()!!
|
||||
} else {
|
||||
val tile = parseTile(program.executeUntilOutput()!!)
|
||||
display.display[y][x] = tile
|
||||
}
|
||||
// display.show()
|
||||
}
|
||||
println(display.score)
|
||||
|
||||
}
|
||||
|
||||
private fun parseTile(output: Long) = when(output) {
|
||||
0L -> Tile.EMPTY
|
||||
1L -> Tile.WALL
|
||||
2L -> Tile.BLOCK
|
||||
3L -> Tile.HORIZONTAL_PADDLE
|
||||
4L -> Tile.BALL
|
||||
else -> throw IllegalArgumentException("Unknown tile type: $output")
|
||||
}
|
||||
|
||||
enum class Tile {
|
||||
EMPTY,
|
||||
WALL,
|
||||
BLOCK,
|
||||
HORIZONTAL_PADDLE,
|
||||
BALL
|
||||
}
|
||||
|
||||
class JoystickInputProvider: InputProvider {
|
||||
|
||||
override fun getInput(): Long {
|
||||
println("Getting input")
|
||||
val key = System.`in`.read()
|
||||
return when (key) {
|
||||
's'.toInt() -> return 0
|
||||
'a'.toInt() -> return -1
|
||||
'd'.toInt() -> return 1
|
||||
10 -> getInput()
|
||||
else -> {
|
||||
println("Unkown key pressed.: $key..")
|
||||
return 0
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class AIInputProvider(val display: Display): InputProvider{
|
||||
|
||||
override fun getInput(): Long {
|
||||
val ballPos = display.find(Tile.BALL)!!
|
||||
val paddlePos = display.find(Tile.HORIZONTAL_PADDLE)!!
|
||||
|
||||
return when {
|
||||
ballPos.x < paddlePos.x -> -1
|
||||
ballPos.x > paddlePos.x -> 1
|
||||
else -> 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class Display(var score: Long, val display: Array<Array<Tile>>) {
|
||||
|
||||
fun find(tile: Tile): Day11.Vector2i? {
|
||||
|
||||
for (y in display.indices) {
|
||||
for (x in display[0].indices) {
|
||||
if (display[y][x] == tile) {
|
||||
return Day11.Vector2i(x, y)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
fun show() {
|
||||
println(score)
|
||||
val maxY = display.indexOfLast { row -> row.any { it != Tile.EMPTY } }
|
||||
val maxX = display.map { row -> row.indexOfLast { it != Tile.EMPTY } }.max()!!
|
||||
for (y in 0..maxY) {
|
||||
for (x in 0..maxX) {
|
||||
print(when(display[y][x]) {
|
||||
Tile.EMPTY -> " "
|
||||
Tile.BLOCK -> "B"
|
||||
Tile.BALL -> "o"
|
||||
Tile.HORIZONTAL_PADDLE -> "-"
|
||||
Tile.WALL -> "#"
|
||||
})
|
||||
}
|
||||
println()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.basdado.adventofcode.day7
|
||||
|
||||
import com.basdado.adventofcode.IntCodeProgram
|
||||
import com.basdado.adventofcode.StackBasedInputProvider
|
||||
import com.basdado.adventofcode.loadProgramData
|
||||
|
||||
const val DAY7_INPUT_PATH = "/day/7/input.txt"
|
||||
@@ -20,7 +21,7 @@ object Day7 {
|
||||
|
||||
for (A in 0L..4) {
|
||||
|
||||
val programA = IntCodeProgram(programData.clone(), longArrayOf(A, 0))
|
||||
val programA = IntCodeProgram(programData.clone(), StackBasedInputProvider(longArrayOf(A, 0)))
|
||||
programA.execute()
|
||||
val outputA = programA.getOutputs().last()
|
||||
|
||||
@@ -28,7 +29,7 @@ object Day7 {
|
||||
|
||||
if (B == A) continue
|
||||
|
||||
val programB = IntCodeProgram(programData.clone(), longArrayOf(B, outputA))
|
||||
val programB = IntCodeProgram(programData.clone(), StackBasedInputProvider(longArrayOf(B, outputA)))
|
||||
programB.execute()
|
||||
val outputB = programB.getOutputs().last()
|
||||
|
||||
@@ -36,7 +37,7 @@ object Day7 {
|
||||
|
||||
if (C == A || C == B) continue
|
||||
|
||||
val programC = IntCodeProgram(programData.clone(), longArrayOf(C, outputB))
|
||||
val programC = IntCodeProgram(programData.clone(), StackBasedInputProvider(longArrayOf(C, outputB)))
|
||||
programC.execute()
|
||||
val outputC = programC.getOutputs().last()
|
||||
|
||||
@@ -44,7 +45,7 @@ object Day7 {
|
||||
|
||||
if (D == A || D == B || D == C) continue
|
||||
|
||||
val programD = IntCodeProgram(programData.clone(), longArrayOf(D, outputC))
|
||||
val programD = IntCodeProgram(programData.clone(), StackBasedInputProvider(longArrayOf(D, outputC)))
|
||||
programD.execute()
|
||||
val outputD = programD.getOutputs().last()
|
||||
|
||||
@@ -52,7 +53,7 @@ object Day7 {
|
||||
|
||||
if (E == A || E == B || E == C || E == D) continue
|
||||
|
||||
val programE = IntCodeProgram(programData.clone(), longArrayOf(E, outputD))
|
||||
val programE = IntCodeProgram(programData.clone(), StackBasedInputProvider(longArrayOf(E, outputD)))
|
||||
programE.execute()
|
||||
val outputE = programE.getOutputs().last()
|
||||
// Beautiful
|
||||
@@ -98,25 +99,31 @@ object Day7 {
|
||||
|
||||
val programData = loadProgramData(DAY7_INPUT_PATH)
|
||||
|
||||
val ampA = IntCodeProgram(programData.clone(), longArrayOf(phaseSettings[0].toLong()))
|
||||
val ampB = IntCodeProgram(programData.clone(), longArrayOf(phaseSettings[1].toLong()))
|
||||
val ampC = IntCodeProgram(programData.clone(), longArrayOf(phaseSettings[2].toLong()))
|
||||
val ampD = IntCodeProgram(programData.clone(), longArrayOf(phaseSettings[3].toLong()))
|
||||
val ampE = IntCodeProgram(programData.clone(), longArrayOf(phaseSettings[4].toLong()))
|
||||
val stackA = StackBasedInputProvider(longArrayOf(phaseSettings[0].toLong()))
|
||||
val stackB = StackBasedInputProvider(longArrayOf(phaseSettings[1].toLong()))
|
||||
val stackC = StackBasedInputProvider(longArrayOf(phaseSettings[2].toLong()))
|
||||
val stackD = StackBasedInputProvider(longArrayOf(phaseSettings[3].toLong()))
|
||||
val stackE = StackBasedInputProvider(longArrayOf(phaseSettings[4].toLong()))
|
||||
|
||||
val ampA = IntCodeProgram(programData.clone(), stackA)
|
||||
val ampB = IntCodeProgram(programData.clone(), stackB)
|
||||
val ampC = IntCodeProgram(programData.clone(), stackC)
|
||||
val ampD = IntCodeProgram(programData.clone(), stackD)
|
||||
val ampE = IntCodeProgram(programData.clone(), stackE)
|
||||
|
||||
|
||||
var ampAInput = 0L
|
||||
var anyAmpRunning = true
|
||||
while (anyAmpRunning) {
|
||||
ampA.pushInput(ampAInput)
|
||||
stackA.pushInput(ampAInput)
|
||||
val ampBInput = ampA.executeUntilOutput() ?: ampA.getOutputs().last()
|
||||
ampB.pushInput(ampBInput)
|
||||
stackB.pushInput(ampBInput)
|
||||
val ampCInput = ampB.executeUntilOutput() ?: ampA.getOutputs().last()
|
||||
ampC.pushInput(ampCInput)
|
||||
stackC.pushInput(ampCInput)
|
||||
val ampDInput = ampC.executeUntilOutput() ?: ampA.getOutputs().last()
|
||||
ampD.pushInput(ampDInput)
|
||||
stackD.pushInput(ampDInput)
|
||||
val ampEInput = ampD.executeUntilOutput() ?: ampA.getOutputs().last()
|
||||
ampE.pushInput(ampEInput)
|
||||
stackE.pushInput(ampEInput)
|
||||
ampAInput = ampE.executeUntilOutput() ?: ampA.getOutputs().last()
|
||||
|
||||
anyAmpRunning = !ampA.done || !ampB.done || !ampC.done || !ampD.done || !ampE.done
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.basdado.adventofcode.day9
|
||||
|
||||
import com.basdado.adventofcode.IntCodeProgram
|
||||
import com.basdado.adventofcode.StackBasedInputProvider
|
||||
import com.basdado.adventofcode.loadProgramData
|
||||
|
||||
const val DAY9_INPUT_PATH = "/day/9/input.txt"
|
||||
@@ -16,7 +17,7 @@ object Day9 {
|
||||
fun puzzle1() {
|
||||
|
||||
val programData = loadProgramData(DAY9_INPUT_PATH)
|
||||
val program = IntCodeProgram(programData + LongArray(65536), longArrayOf(1))
|
||||
val program = IntCodeProgram(programData + LongArray(65536), StackBasedInputProvider(longArrayOf(1)))
|
||||
program.execute()
|
||||
println(program.getOutputs())
|
||||
}
|
||||
@@ -24,7 +25,7 @@ object Day9 {
|
||||
fun puzzle2() {
|
||||
|
||||
val programData = loadProgramData(DAY9_INPUT_PATH)
|
||||
val program = IntCodeProgram(programData + LongArray(65536), longArrayOf(2))
|
||||
val program = IntCodeProgram(programData + LongArray(65536), StackBasedInputProvider(longArrayOf(2)))
|
||||
program.execute()
|
||||
println(program.getOutputs())
|
||||
}
|
||||
|
||||
1
src/main/resources/day/13/input.txt
Normal file
1
src/main/resources/day/13/input.txt
Normal file
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user