Day 13, that was really cool!

This commit is contained in:
2019-12-15 01:44:15 +01:00
parent a5dfc7cbd2
commit 190dd4bc9b
6 changed files with 201 additions and 30 deletions

View File

@@ -1,5 +1,7 @@
package com.basdado.adventofcode package com.basdado.adventofcode
import java.lang.UnsupportedOperationException
val FULL_OPCODES = mapOf( val FULL_OPCODES = mapOf(
Pair(1L, OpCode(1L, 3, ::add)), Pair(1L, OpCode(1L, 3, ::add)),
Pair(2L, OpCode(2L, 3, ::multiply)), 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 { 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 { fun loadProgramData(inputPath: String): LongArray {
return line(inputPath).split(",").map { it.toLong() }.toLongArray() return line(inputPath).split(",").map { it.toLong() }.toLongArray()
} }
class IntCodeProgram(val data: LongArray, var inputs: LongArray, val opCodes: Map<Long, OpCode> = FULL_OPCODES, interface InputProvider {
var pointer: Int = 0) { fun getInput(): Long
}
class StackBasedInputProvider(var inputs: LongArray = longArrayOf()): InputProvider {
private var inputPointer: Int = 0 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 var relativeBase: Long = 0
private val outputs = mutableListOf<Long>() private val outputs = mutableListOf<Long>()
var done = false var done = false
@@ -50,12 +74,9 @@ class IntCodeProgram(val data: LongArray, var inputs: LongArray, val opCodes: Ma
} }
fun getNextInput(): Long { fun getNextInput(): Long {
return inputs[inputPointer++] return inputProvider.getInput()
} }
fun pushInput(input: Long) {
inputs += input
}
fun getOutputs(): List<Long> { fun getOutputs(): List<Long> {
return outputs return outputs
} }

View File

@@ -1,6 +1,7 @@
package com.basdado.adventofcode.day11 package com.basdado.adventofcode.day11
import com.basdado.adventofcode.IntCodeProgram import com.basdado.adventofcode.IntCodeProgram
import com.basdado.adventofcode.StackBasedInputProvider
import com.basdado.adventofcode.loadProgramData import com.basdado.adventofcode.loadProgramData
const val DAY11_INPUT_PATH = "/day/11/input.txt" const val DAY11_INPUT_PATH = "/day/11/input.txt"
@@ -14,9 +15,10 @@ object Day11 {
fun puzzle1() { fun puzzle1() {
val programData = loadProgramData(DAY11_INPUT_PATH) 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>() val hull = mutableMapOf<Vector2i, Int>()
paintHull(hull, program) paintHull(hull, program, inputProvider)
printHull(hull) printHull(hull)
println(hull.size) println(hull.size)
} }
@@ -24,12 +26,13 @@ object Day11 {
fun puzzle2() { fun puzzle2() {
val programData = loadProgramData(DAY11_INPUT_PATH) 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>( val hull = mutableMapOf<Vector2i, Int>(
// Paint position 0,0 white // Paint position 0,0 white
Pair(Vector2i(0, 0), 1) Pair(Vector2i(0, 0), 1)
) )
paintHull(hull, program) paintHull(hull, program, inputProvider)
printHull(hull) printHull(hull)
} }
@@ -59,7 +62,8 @@ object Day11 {
private fun paintHull( private fun paintHull(
hull: MutableMap<Vector2i, Int>, hull: MutableMap<Vector2i, Int>,
program: IntCodeProgram program: IntCodeProgram,
inputProvider: StackBasedInputProvider
) { ) {
var pos = Vector2i(0, 0) var pos = Vector2i(0, 0)
var dir = UP var dir = UP
@@ -69,7 +73,7 @@ object Day11 {
while (hullPaintingSizeConstant < 1000) { while (hullPaintingSizeConstant < 1000) {
lastHullPaintingSize = hull.size lastHullPaintingSize = hull.size
program.pushInput((hull[pos] ?: 0).toLong()) inputProvider.pushInput((hull[pos] ?: 0).toLong())
val color = program.executeUntilOutput() ?: break val color = program.executeUntilOutput() ?: break
hull[pos] = color.toInt() hull[pos] = color.toInt()

View 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()
}
}
}
}

View File

@@ -1,6 +1,7 @@
package com.basdado.adventofcode.day7 package com.basdado.adventofcode.day7
import com.basdado.adventofcode.IntCodeProgram import com.basdado.adventofcode.IntCodeProgram
import com.basdado.adventofcode.StackBasedInputProvider
import com.basdado.adventofcode.loadProgramData import com.basdado.adventofcode.loadProgramData
const val DAY7_INPUT_PATH = "/day/7/input.txt" const val DAY7_INPUT_PATH = "/day/7/input.txt"
@@ -20,7 +21,7 @@ object Day7 {
for (A in 0L..4) { for (A in 0L..4) {
val programA = IntCodeProgram(programData.clone(), longArrayOf(A, 0)) val programA = IntCodeProgram(programData.clone(), StackBasedInputProvider(longArrayOf(A, 0)))
programA.execute() programA.execute()
val outputA = programA.getOutputs().last() val outputA = programA.getOutputs().last()
@@ -28,7 +29,7 @@ object Day7 {
if (B == A) continue if (B == A) continue
val programB = IntCodeProgram(programData.clone(), longArrayOf(B, outputA)) val programB = IntCodeProgram(programData.clone(), StackBasedInputProvider(longArrayOf(B, outputA)))
programB.execute() programB.execute()
val outputB = programB.getOutputs().last() val outputB = programB.getOutputs().last()
@@ -36,7 +37,7 @@ object Day7 {
if (C == A || C == B) continue 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() programC.execute()
val outputC = programC.getOutputs().last() val outputC = programC.getOutputs().last()
@@ -44,7 +45,7 @@ object Day7 {
if (D == A || D == B || D == C) continue 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() programD.execute()
val outputD = programD.getOutputs().last() val outputD = programD.getOutputs().last()
@@ -52,7 +53,7 @@ object Day7 {
if (E == A || E == B || E == C || E == D) continue 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() programE.execute()
val outputE = programE.getOutputs().last() val outputE = programE.getOutputs().last()
// Beautiful // Beautiful
@@ -98,25 +99,31 @@ object Day7 {
val programData = loadProgramData(DAY7_INPUT_PATH) val programData = loadProgramData(DAY7_INPUT_PATH)
val ampA = IntCodeProgram(programData.clone(), longArrayOf(phaseSettings[0].toLong())) val stackA = StackBasedInputProvider(longArrayOf(phaseSettings[0].toLong()))
val ampB = IntCodeProgram(programData.clone(), longArrayOf(phaseSettings[1].toLong())) val stackB = StackBasedInputProvider(longArrayOf(phaseSettings[1].toLong()))
val ampC = IntCodeProgram(programData.clone(), longArrayOf(phaseSettings[2].toLong())) val stackC = StackBasedInputProvider(longArrayOf(phaseSettings[2].toLong()))
val ampD = IntCodeProgram(programData.clone(), longArrayOf(phaseSettings[3].toLong())) val stackD = StackBasedInputProvider(longArrayOf(phaseSettings[3].toLong()))
val ampE = IntCodeProgram(programData.clone(), longArrayOf(phaseSettings[4].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 ampAInput = 0L
var anyAmpRunning = true var anyAmpRunning = true
while (anyAmpRunning) { while (anyAmpRunning) {
ampA.pushInput(ampAInput) stackA.pushInput(ampAInput)
val ampBInput = ampA.executeUntilOutput() ?: ampA.getOutputs().last() val ampBInput = ampA.executeUntilOutput() ?: ampA.getOutputs().last()
ampB.pushInput(ampBInput) stackB.pushInput(ampBInput)
val ampCInput = ampB.executeUntilOutput() ?: ampA.getOutputs().last() val ampCInput = ampB.executeUntilOutput() ?: ampA.getOutputs().last()
ampC.pushInput(ampCInput) stackC.pushInput(ampCInput)
val ampDInput = ampC.executeUntilOutput() ?: ampA.getOutputs().last() val ampDInput = ampC.executeUntilOutput() ?: ampA.getOutputs().last()
ampD.pushInput(ampDInput) stackD.pushInput(ampDInput)
val ampEInput = ampD.executeUntilOutput() ?: ampA.getOutputs().last() val ampEInput = ampD.executeUntilOutput() ?: ampA.getOutputs().last()
ampE.pushInput(ampEInput) stackE.pushInput(ampEInput)
ampAInput = ampE.executeUntilOutput() ?: ampA.getOutputs().last() ampAInput = ampE.executeUntilOutput() ?: ampA.getOutputs().last()
anyAmpRunning = !ampA.done || !ampB.done || !ampC.done || !ampD.done || !ampE.done anyAmpRunning = !ampA.done || !ampB.done || !ampC.done || !ampD.done || !ampE.done

View File

@@ -1,6 +1,7 @@
package com.basdado.adventofcode.day9 package com.basdado.adventofcode.day9
import com.basdado.adventofcode.IntCodeProgram import com.basdado.adventofcode.IntCodeProgram
import com.basdado.adventofcode.StackBasedInputProvider
import com.basdado.adventofcode.loadProgramData import com.basdado.adventofcode.loadProgramData
const val DAY9_INPUT_PATH = "/day/9/input.txt" const val DAY9_INPUT_PATH = "/day/9/input.txt"
@@ -16,7 +17,7 @@ object Day9 {
fun puzzle1() { fun puzzle1() {
val programData = loadProgramData(DAY9_INPUT_PATH) 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() program.execute()
println(program.getOutputs()) println(program.getOutputs())
} }
@@ -24,7 +25,7 @@ object Day9 {
fun puzzle2() { fun puzzle2() {
val programData = loadProgramData(DAY9_INPUT_PATH) 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() program.execute()
println(program.getOutputs()) println(program.getOutputs())
} }

File diff suppressed because one or more lines are too long