Skip to content

Commit

Permalink
Y2019
Browse files Browse the repository at this point in the history
Copied 2019 solutions from old repo, without editing

https://github.com/hibob224/aoc2019
  • Loading branch information
hibob224 committed Dec 21, 2024
1 parent 1a62f41 commit 84e045e
Show file tree
Hide file tree
Showing 43 changed files with 1,148 additions and 6 deletions.
4 changes: 1 addition & 3 deletions src/main/kotlin/utils/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -124,9 +124,7 @@ fun List<Long>.gcd(): Long = reduce { x, y -> gcd(x, y) }
fun lcm(x: Long, y: Long): Long = x * (y / gcd(x, y))
fun List<Long>.lcm(): Long = reduce { x, y -> lcm(x, y) }

fun Any.getInputFile(example: Boolean = false): File = getInputFile()

@Deprecated("Use alternate that doesn't take package name", replaceWith = ReplaceWith("getInputFile()"))
fun Any.getInputFile(example: Boolean = false): File = getInputFile(this::class.java.packageName, example)
private fun getInputFile(packageName: String, example: Boolean = false): File = File("src/main/kotlin/${packageName.replace('.', '/')}/${if (example) "example" else "input"}.txt")

fun <T> List<T>.permutations(): List<List<T>> {
Expand Down
117 changes: 117 additions & 0 deletions src/main/kotlin/y2019/IntCodeComputer.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
import java.util.concurrent.BlockingQueue
import java.util.concurrent.Callable
import java.util.concurrent.LinkedBlockingQueue

typealias Input = () -> Long
typealias Output = (Long) -> Unit

class IntCodeComputer(
inpMemory: LongArray,
var latestOutput: Long = -1
) : Callable<Long> {

private val memory = LongArray(10000) { 0 }
private val inputs = LinkedBlockingQueue<Long>()
var outputComputer: IntCodeComputer? = null
var outputArray: BlockingQueue<Long>? = null
var input: Input? = null
var output: Output? = null

init {
inpMemory.copyInto(memory)
}

fun addInput(vararg input: Long) {
inputs.addAll(input.toList())
}

override fun call(): Long {
var position = 0
var relativeBase = 0

do {
val opcode = memory[position].toString().padStart(5, '0')
val parsedOpcode = opcode.substring(opcode.lastIndex.dec()).toInt()
val modes = mutableListOf(
opcode[0].toString().toInt(),
opcode[1].toString().toInt(),
opcode[2].toString().toInt()
)

val inp1 = when (modes[2]) {
0 -> memory.getOrElse(memory.getOrElse(position.inc()) { 0L }.toInt()) { 0L }
1 -> memory.getOrElse(position.inc()) { 0L }
2 -> memory.getOrElse(memory.getOrElse(position.inc()) { 0L }.toInt() + relativeBase) { 0L }
else -> throw IllegalArgumentException("Fucked")
}
val inp2 = when (modes[1]) {
0 -> memory.getOrElse(memory.getOrElse(position.inc().inc()) { 0L }.toInt()) { 0L }
1 -> memory.getOrElse(position.inc().inc()) { 0L }
2 -> memory.getOrElse(memory.getOrElse(position.inc().inc()) { 0L }.toInt() + relativeBase) { 0L }
else -> throw IllegalArgumentException("Fucked")
}
val inp3 = when (modes[0]) {
0, 1 -> memory.getOrElse(position.inc().inc().inc()) { 0L }
2 -> memory.getOrElse(position.inc().inc().inc()) { 0L } + relativeBase
else -> throw IllegalArgumentException("Fucked")
}.toInt()

when (parsedOpcode) {
1 -> {
memory[inp3] = inp1 + inp2
position += 4
}
2 -> {
memory[inp3] = inp1 * inp2
position += 4
}
3 -> {
val out = when (modes[2]) {
0, 1 -> memory.getOrElse(position.inc()) { 0L }
2 -> memory.getOrElse(position.inc()) { 0L } + relativeBase
else -> throw IllegalArgumentException("Fucked")
}.toInt()
input?.let {
memory[out] = it.invoke()
} ?: kotlin.run { memory[out] = inputs.take() }
position += 2
}
4 -> {
latestOutput = inp1
output?.invoke(inp1)
outputComputer?.inputs?.add(inp1)
outputArray?.add(inp1)
position += 2
}
5 -> {
if (inp1 != 0L) {
position = inp2.toInt()
} else {
position += 3
}
}
6 -> {
if (inp1 == 0L) {
position = inp2.toInt()
} else {
position += 3
}
}
7 -> {
memory[inp3] = if (inp1 < inp2) 1L else 0L
position += 4
}
8 -> {
memory[inp3] = if (inp1 == inp2) 1L else 0L
position += 4
}
9 -> {
relativeBase += inp1.toInt()
position += 2
}
99 -> return latestOutput
else -> throw IllegalStateException("Unknown opcode $opcode")
}
} while (true)
}
}
30 changes: 30 additions & 0 deletions src/main/kotlin/y2019/day01/Day1.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package y2019.day01

import utils.getInputFile
import utils.orZero

fun main() {
println("Part one: ${Day1.solvePartOne()}")
println("Part two: ${Day1.solvePartTwo()}")
}

object Day1 {

private val moduleMasses = getInputFile().readLines().map(String::toInt)

fun solvePartOne(): String = moduleMasses.sumBy { calculateRequiredFuel(it) }.toString()

fun solvePartTwo(): String {
return moduleMasses.fold(0) { acc, mass ->
var requiredFuel = 0
var temp = mass
while (temp > 0) {
temp = calculateRequiredFuel(temp)
requiredFuel += temp
}
acc + requiredFuel
}.toString()
}

private fun calculateRequiredFuel(mass: Int) = (mass / 3 - 2).takeIf { it > 0 }.orZero()
}
Binary file added src/main/kotlin/y2019/day01/input.txt
Binary file not shown.
54 changes: 54 additions & 0 deletions src/main/kotlin/y2019/day02/Day2.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
package y2019.day02

import utils.getInputFile

fun main() {
println("Part one: ${Day2.solvePartOne()}")
println("Part two: ${Day2.solvePartTwo()}")
}

object Day2 {

private val input = getInputFile().readText().split(",").map(String::toInt)

fun solvePartOne(): String {
val partOneInput = ArrayList(input)
partOneInput[1] = 12
partOneInput[2] = 2
return runProgram(partOneInput).toString()
}

fun solvePartTwo(): String {
for (n in 0..99) {
for (v in 0..99) {
val input = ArrayList(input)
input[1] = n
input[2] = v
val output = runProgram(input)
if (output == 19690720) {
return (100 * n + v).toString()
}
}
}
throw IllegalStateException("Didn't find answer")
}

private fun runProgram(input: ArrayList<Int>): Int {
var position = 0
do {
val opcode = input[position]
val inp1 = input[position.inc()]
val inp2 = input[position.inc().inc()]
val out = input[position.inc().inc().inc()]

when (opcode) {
1 -> input[out] = input[inp1] + input[inp2]
2 -> input[out] = input[inp1] * input[inp2]
99 -> return input[0]
else -> return -1 // Exception
}

position += 4
} while (true)
}
}
Binary file added src/main/kotlin/y2019/day02/input.txt
Binary file not shown.
59 changes: 59 additions & 0 deletions src/main/kotlin/y2019/day03/Day3.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package y2019.day03

import utils.Point
import utils.getInputFile
import kotlin.math.abs

fun main() {
println("Part one: ${Day3.solvePartOne()}")
println("Part two: ${Day3.solvePartTwo()}")
}

object Day3 {

private val lineOne = mutableListOf(Wire(0, 0))
private val lineTwo = mutableListOf(Wire(0, 0))

init {
val lineOneInput = parseInput()[0]
val lineTwoInput = parseInput()[1]
lineOneInput.forEach { lineOne.addAll(lineOne.last().move(it)) }
lineTwoInput.forEach { lineTwo.addAll(lineTwo.last().move(it)) }
lineOne.removeAt(0)
lineTwo.removeAt(0)
}

private fun parseInput(): List<List<String>> =
getInputFile().readLines().map { it.split(",") }

fun solvePartOne(): String = lineOne.intersect(lineTwo.toSet()).minOfOrNull { it.distanceFromOrigin() }.toString()

fun solvePartTwo(): String = lineOne.intersect(lineTwo.toSet()).minOfOrNull { intersect ->
lineOne.first { intersect == it }.steps + lineTwo.first { intersect == it }.steps
}.toString()

// Basically just Point, but have copied in this solution years later so, not fixing it now
private data class Wire(val x: Int, val y: Int) {

var steps = 0

fun move(movement: String): List<Wire> {
val direction = movement.first()
val steps = movement.substring(1).toInt()

return (1..steps).map { step ->
when (direction) {
'R' -> copy(x = x + step)
'L' -> copy(x = x - step)
'U' -> copy(y = y - step)
'D' -> copy(y = y + step)
else -> throw IllegalArgumentException("Unknown movement type")
}.also { it.steps += this.steps + step }
}
}

fun distanceFromOrigin(): Int = manhattan(Point(0, 0))

fun manhattan(other: Point): Int = abs(x - other.x) + abs(y - other.y)
}
}
Binary file added src/main/kotlin/y2019/day03/input.txt
Binary file not shown.
34 changes: 34 additions & 0 deletions src/main/kotlin/y2019/day04/Day4.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package y2019.day04

import utils.orFalse

fun main() {
println("Part one: ${Day4.solvePartOne()}")
println("Part two: ${Day4.solvePartTwo()}")
}

object Day4 {

private val range = 240920..789857

fun solvePartOne(): String {
return range.count { pw ->
val zipped = pw.toString().zipWithNext()
zipped.all { it.first <= it.second } &&
zipped.any { it.first == it.second }
}.toString()
}

fun solvePartTwo(): String {
return range.count { pw ->
val zipped = pw.toString().zipWithNext()
zipped.all { it.first <= it.second } &&
zipped.filter { it.first == it.second }
.groupBy { it.first }
.entries
.takeIf { it.isNotEmpty() }
?.any { it.value.size == 1 }
.orFalse()
}.toString()
}
}
21 changes: 21 additions & 0 deletions src/main/kotlin/y2019/day05/Day5.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package y2019.day05

import IntCodeComputer
import utils.getInputFile

fun main() {
println("Part one: ${Day5.solvePartOne()}")
println("Parse two: ${Day5.solvePartTwo()}")
}

object Day5 {

private fun parseInput(): List<Long> = getInputFile()
.readLines()[0]
.split(",")
.map { it.toLong() }

fun solvePartOne(): String = IntCodeComputer(parseInput().toLongArray()).also { it.addInput(1) }.call().toString()

fun solvePartTwo(): String = IntCodeComputer(parseInput().toLongArray()).also { it.addInput(5) }.call().toString()
}
Binary file added src/main/kotlin/y2019/day05/input.txt
Binary file not shown.
63 changes: 63 additions & 0 deletions src/main/kotlin/y2019/day06/Day6.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
package y2019.day06

import utils.getInputFile

fun main() {
println("Part one: ${Day6.solvePartOne()}")
println("Part two: ${Day6.solvePartTwo()}")
}

object Day6 {

private fun parseInput(): Map<String, List<String>> =
getInputFile()
.readLines()
.map { it.split(")")[0] to it.split(")")[1] }
.groupBy({ it.first }) { it.second }

fun solvePartOne(): String {
val input = parseInput()
var count = 0

input.forEach {
count += it.value.size
val multiplier = it.value.size
var target = it.key
while (true) {
input.entries.find { it.value.contains(target) }?.let {
count += 1 * multiplier
target = it.key
} ?: break
}
}

return count.toString()
}

fun solvePartTwo(): String {
val input = parseInput()
val youLoc = input.entries.find { it.value.contains("YOU") }!!.key
val santaLoc = input.entries.find { it.value.contains("SAN") }!!.key

val steps = mutableListOf(listOf(youLoc))

while (true) {
var newFrontline = mutableListOf<String>()

newFrontline.addAll(steps.last().flatMap { input[it].orEmpty() }) // Add all objects that orbit our current objects
newFrontline.addAll(steps.last().mapNotNull { loc -> // Add all our direct orbits
input.entries.find { it.value.contains(loc) }?.key
})
newFrontline = newFrontline.filterNot { steps.flatten().contains(it) }.toMutableList() // Make sure we're not checking locations we've checked before
newFrontline = newFrontline.distinct().toMutableList() // Remove duplicates
steps.add(newFrontline)
if (newFrontline.contains(santaLoc)) {
// We've found Santa!
break
}
}

// Decrease steps by 1 because we don't count the starting location
return steps.size.dec().toString()
}
}
Binary file added src/main/kotlin/y2019/day06/input.txt
Binary file not shown.
Loading

0 comments on commit 84e045e

Please sign in to comment.