diff --git a/src/main/kotlin/me/gergo/Aoc01.kt b/src/main/kotlin/me/gergo/Aoc01.kt index 59df70e..fe4b74a 100644 --- a/src/main/kotlin/me/gergo/Aoc01.kt +++ b/src/main/kotlin/me/gergo/Aoc01.kt @@ -23,6 +23,6 @@ fun main() { .sumOf { it.calories }) } -class Elf { +private class Elf { var calories = 0; } \ No newline at end of file diff --git a/src/main/kotlin/me/gergo/Aoc02.kt b/src/main/kotlin/me/gergo/Aoc02.kt index 76511c9..52b9c7a 100644 --- a/src/main/kotlin/me/gergo/Aoc02.kt +++ b/src/main/kotlin/me/gergo/Aoc02.kt @@ -11,7 +11,7 @@ fun main() { } enum class Choice { Rock, Paper, Scissors } -data class Guide(val opponent: Choice, val my: Choice) { +private data class Guide(val opponent: Choice, val my: Choice) { fun score(): Int = scoreFor(my) + scoreForOutcomeOf(opponent, my) private fun scoreFor(c: Choice): Int = c.ordinal + 1 @@ -24,7 +24,7 @@ data class Guide(val opponent: Choice, val my: Choice) { } } -fun parseGuide(line: String): Guide { +private fun parseGuide(line: String): Guide { val tokens = line.split(" ") val opponent = when (tokens[0]) { "A" -> Rock diff --git a/src/main/kotlin/me/gergo/Aoc02b.kt b/src/main/kotlin/me/gergo/Aoc02b.kt index 84e2b78..5e587cf 100644 --- a/src/main/kotlin/me/gergo/Aoc02b.kt +++ b/src/main/kotlin/me/gergo/Aoc02b.kt @@ -13,8 +13,8 @@ fun main() { private val Choices = Choice.values() -enum class Result { Lose, Draw, Win } -data class Guide2(val opponent: Choice, val result: Result) { +private enum class Result { Lose, Draw, Win } +private data class Guide2(val opponent: Choice, val result: Result) { fun score(): Int = scoreFor(pickChoiceFor(opponent, result)) + scoreFor(result) private fun scoreFor(r: Result): Int = when (r) { @@ -31,7 +31,7 @@ data class Guide2(val opponent: Choice, val result: Result) { } } -fun parseGuide2(line: String): Guide2 { +private fun parseGuide2(line: String): Guide2 { val tokens = line.split(" ") val opponent = when (tokens[0]) { "A" -> Rock diff --git a/src/main/kotlin/me/gergo/Aoc03.kt b/src/main/kotlin/me/gergo/Aoc03.kt index a76a743..cf42de0 100644 --- a/src/main/kotlin/me/gergo/Aoc03.kt +++ b/src/main/kotlin/me/gergo/Aoc03.kt @@ -12,22 +12,22 @@ fun main() { println(results) } -data class Rucksack(val c1: String, val c2: String) { +private data class Rucksack(val c1: String, val c2: String) { fun priorityOfSharedType() = priorityOf(sharedType()) // For Part One private fun sharedType(): Char = c1.toCharArray().intersect(c2.toCharArray().toSet()).first() } -fun parseRucksack(line: String): Rucksack { +private fun parseRucksack(line: String): Rucksack { return Rucksack(line.substring(0, line.length / 2), line.substring(line.length / 2)) } -fun priorityOfSharedType(group: Iterable): Int { +private fun priorityOfSharedType(group: Iterable): Int { val sharedType = group.map { (it.c1 + it.c2).toCharArray().toSet() }.reduce { acc, r -> acc.intersect(r) }.first() return priorityOf(sharedType) } -fun priorityOf(type: Char): Int { +private fun priorityOf(type: Char): Int { val d = type.code return if (d >= 'a'.code && d <= 'z'.code) d - 'a'.code + 1 else d - 'A'.code + 27 diff --git a/src/main/kotlin/me/gergo/Aoc04.kt b/src/main/kotlin/me/gergo/Aoc04.kt index d74bad3..1e64b81 100644 --- a/src/main/kotlin/me/gergo/Aoc04.kt +++ b/src/main/kotlin/me/gergo/Aoc04.kt @@ -11,12 +11,12 @@ fun main() { println(results) } -data class Assignment(val first: IntRange, val second: IntRange) { +private data class Assignment(val first: IntRange, val second: IntRange) { fun fullyContains() = first.minus(second).isEmpty() || second.minus(first).isEmpty() fun overlaps() = first.minus(second).size < first.count() || second.minus(first).size < second.count() } -fun parseAssignment(line: String): Assignment { +private fun parseAssignment(line: String): Assignment { val ranges = line.split(",").map { val range = it.split("-").map(String::toInt) range[0]..range[1] diff --git a/src/main/kotlin/me/gergo/Aoc05.kt b/src/main/kotlin/me/gergo/Aoc05.kt index de7d9ae..32db9b3 100644 --- a/src/main/kotlin/me/gergo/Aoc05.kt +++ b/src/main/kotlin/me/gergo/Aoc05.kt @@ -16,17 +16,17 @@ fun main() { stacks.forEach { print(it.peek()) } } -typealias CrateStack = Stack +private typealias CrateStack = Stack -data class Instruction(val quantity: Int, val fromStack: Int, val toStack: Int) {} +private data class Instruction(val quantity: Int, val fromStack: Int, val toStack: Int) {} -fun parseStacksAndInstructions(lines: List): Pair, List> { +private fun parseStacksAndInstructions(lines: List): Pair, List> { val stacks = parseStacks(lines.subList(0, lines.indexOf("") - 1)) val instructions = lines.subList(lines.indexOf("") + 1, lines.size).map(::parseInstruction) return Pair(stacks, instructions) } -fun parseStacks(lines: List): List { +private fun parseStacks(lines: List): List { val stackCount = (lines[0].length + 1) / 4 val result = List(stackCount) { Stack() } for (i in lines.size - 1 downTo 0) { @@ -41,7 +41,7 @@ fun parseStacks(lines: List): List { return result } -fun parseInstruction(line: String): Instruction { +private fun parseInstruction(line: String): Instruction { val m = Regex("move (\\d+) from (\\d+) to (\\d+)").matchEntire(line)!! return Instruction(m.groupValues[1].toInt(), m.groupValues[2].toInt(), m.groupValues[3].toInt()) } diff --git a/src/main/kotlin/me/gergo/Aoc07.kt b/src/main/kotlin/me/gergo/Aoc07.kt index ec09ac2..e415af4 100644 --- a/src/main/kotlin/me/gergo/Aoc07.kt +++ b/src/main/kotlin/me/gergo/Aoc07.kt @@ -40,7 +40,7 @@ fun main() { println("To delete: $toDelete, totalSize=${toDelete.totalSize()}") } -fun parseCommandLine(line: String): CommandLine { +private fun parseCommandLine(line: String): CommandLine { return if (line == "$ ls") Ls else if (line.startsWith("$ cd")) Cd(line.substring(5)) else if (line.startsWith("dir ")) DirectoryOutput(line.substring(4)) @@ -50,13 +50,13 @@ fun parseCommandLine(line: String): CommandLine { } } -sealed interface CommandLine -object Ls : CommandLine {} -data class Cd(val dirName: String) : CommandLine {} -data class DirectoryOutput(val name: String) : CommandLine {} -data class FileOutput(val name: String, val size: Int) : CommandLine {} +private sealed interface CommandLine +private object Ls : CommandLine {} +private data class Cd(val dirName: String) : CommandLine {} +private data class DirectoryOutput(val name: String) : CommandLine {} +private data class FileOutput(val name: String, val size: Int) : CommandLine {} -data class FileNode(val name: String, val size: Int, var parent: FileNode?, val children: MutableList) { +private data class FileNode(val name: String, val size: Int, var parent: FileNode?, val children: MutableList) { fun isDirectory() = children.size > 0 diff --git a/src/main/kotlin/me/gergo/Aoc08.kt b/src/main/kotlin/me/gergo/Aoc08.kt index 6886873..eb2820e 100644 --- a/src/main/kotlin/me/gergo/Aoc08.kt +++ b/src/main/kotlin/me/gergo/Aoc08.kt @@ -11,7 +11,7 @@ fun main() { println("Max scenic score: ${trees.maxScenicScore()}") // Part Two } -class Trees(lines: List) { +private class Trees(lines: List) { private val forest: Array private val width: Int private val height: Int diff --git a/src/main/kotlin/me/gergo/Aoc09.kt b/src/main/kotlin/me/gergo/Aoc09.kt index 18fab08..05d840b 100644 --- a/src/main/kotlin/me/gergo/Aoc09.kt +++ b/src/main/kotlin/me/gergo/Aoc09.kt @@ -18,13 +18,13 @@ fun main() { println("Positions visited by tail: ${ropeField.positionsVisitedByTail().count()}") } -enum class Direction { L, R, U, D } -data class RopeStep(val dir: Direction, val steps: Int) -data class Position(val x: Int, val y: Int) { +private enum class Direction { L, R, U, D } +private data class RopeStep(val dir: Direction, val steps: Int) +private data class Position(val x: Int, val y: Int) { fun distanceFrom(o: Position) = max(abs(x - o.x), abs(y - o.y)) } -class Rope(internal val knots: MutableList) { +private class Rope(internal val knots: MutableList) { fun head() = knots[0] fun tail() = knots[knots.size - 1] @@ -56,7 +56,7 @@ class Rope(internal val knots: MutableList) { } } -class RopeField(private val width: Int, private val height: Int, ropeLength: Int) { +private class RopeField(private val width: Int, private val height: Int, ropeLength: Int) { private val rope = Rope(MutableList(ropeLength) { Position(0, 0) }) private val tailPositions = mutableListOf() @@ -81,7 +81,7 @@ class RopeField(private val width: Int, private val height: Int, ropeLength: Int fun positionsVisitedByTail() = tailPositions.toSet() } -fun parseRopeStep(line: String): RopeStep { +private fun parseRopeStep(line: String): RopeStep { val (dir, steps) = line.split(" ") return RopeStep(Direction.valueOf(dir), steps.toInt()) } diff --git a/src/main/kotlin/me/gergo/Aoc10.kt b/src/main/kotlin/me/gergo/Aoc10.kt index 6e2a9a2..81cf8ce 100644 --- a/src/main/kotlin/me/gergo/Aoc10.kt +++ b/src/main/kotlin/me/gergo/Aoc10.kt @@ -19,9 +19,9 @@ fun main() { CRT(40, 6, cpu).draw() } -sealed class Instr(val duration: Int) -object Noop : Instr(1) -data class Addx(val value: Int) : Instr(2) +private sealed class Instr(val duration: Int) +private object Noop : Instr(1) +private data class Addx(val value: Int) : Instr(2) private class CPU(private val instructions: List) { private var instructionPointer = 0 @@ -56,7 +56,7 @@ private class CRT(private val width: Int, private val height: Int, private val c } } -fun parseInstr(line: String): Instr { +private fun parseInstr(line: String): Instr { val tokens = line.split(" ") return if (tokens[0] == "noop") Noop else Addx(tokens[1].toInt()) diff --git a/src/main/kotlin/me/gergo/Aoc11.kt b/src/main/kotlin/me/gergo/Aoc11.kt index a2040fc..271acaa 100644 --- a/src/main/kotlin/me/gergo/Aoc11.kt +++ b/src/main/kotlin/me/gergo/Aoc11.kt @@ -7,7 +7,7 @@ private const val Rounds = 10000 /** * Note: this only has Part Two, as I did Part One with a naiive solution that probably takes all the memory in the world, multiplying horribly large - * BigDecimals :) The trick in this one is to remember but delay the computation for as long as possible. As we're only really interested in whether + * BigDecimals :) The trick in this one is to remember to delay the computation for as long as possible. As we're only really interested in whether * the result at the end of a long chain of operations is divisible by N, we can modulo N per every operation - but we must do that for each monkey * individually, which means we must remember the computation chain (Items.operations in this implementation)! * @@ -38,19 +38,6 @@ fun main() { println("Level of monkey business: $result") } -fun lcm(a: Int, b: Int) = a * (b / gcd(a, b)) - -fun gcd(a: Int, b: Int): Int { - var a0 = a - var b0 = b - while (b0 > 0) { - val temp = b0 - b0 = a0 % b0 - a0 = temp - } - return a0 -} - private class Monkey(val name: Int, val items: Queue, val operation: Operation, val divisor: Int, val throwToTrue: Int, val throwToFalse: Int) { var inspections = 0L diff --git a/src/main/kotlin/me/gergo/Aoc12.kt b/src/main/kotlin/me/gergo/Aoc12.kt index e0a8e2b..631404e 100644 --- a/src/main/kotlin/me/gergo/Aoc12.kt +++ b/src/main/kotlin/me/gergo/Aoc12.kt @@ -58,58 +58,4 @@ private operator fun Array.set(c: Coordinate, value: Char) { this[c.y][c.x] = value } -data class Coordinate(val x: Int, val y: Int) - -fun aStar( - start: Coordinate, goal: Coordinate, - neighborFn: (Coordinate) -> Sequence, - heuristicFn: (Coordinate) -> Double, - distanceFn: (Coordinate, Coordinate) -> Double -): List { - val openSet = mutableSetOf(start) - val cameFrom = mutableMapOf() - - val gScore = mutableMapOf() - gScore[start] = 0.0 - - val fScore = mutableMapOf() - fScore[start] = heuristicFn(start) - - while (openSet.isNotEmpty()) { - val current = openSet.minBy { fScore.getOrDefault(it, POSITIVE_INFINITY) } - if (current == goal) { - // Path found, reconstructing - val result = mutableListOf(current) - var c: Coordinate? = current - while (true) { - c = cameFrom[c] - if (c == null) break - result.add(0, c) - } - return result - } - - openSet.remove(current) - for (neighbor in neighborFn(current)) { - val tentativeGScore = gScore.getOrDefault(current, POSITIVE_INFINITY) + distanceFn(current, neighbor) - if (tentativeGScore < gScore.getOrDefault(neighbor, POSITIVE_INFINITY)) { - cameFrom[neighbor] = current - gScore[neighbor] = tentativeGScore - fScore[neighbor] = tentativeGScore + heuristicFn(neighbor) - openSet.add(neighbor) - } - } - } - return emptyList() // Path not found -} - -fun neighbors(width: Int, height: Int, c: Coordinate) = sequence { - val x = c.x - val y = c.y - if (x > 0) yield(Coordinate(x - 1, y)) - if (y + 1 < height) yield(Coordinate(x, y + 1)) - if (x + 1 < width) yield(Coordinate(x + 1, y)) - if (y > 0) yield(Coordinate(x, y - 1)) -} - private fun manhattanDistance(a: Coordinate, b: Coordinate): Double = (abs(b.x - a.x) + abs(b.y - a.y)).toDouble() diff --git a/src/main/kotlin/me/gergo/coordinates.kt b/src/main/kotlin/me/gergo/coordinates.kt new file mode 100644 index 0000000..43117e9 --- /dev/null +++ b/src/main/kotlin/me/gergo/coordinates.kt @@ -0,0 +1,15 @@ +package me.gergo + +import kotlin.math.abs + +data class Coordinate(val x: Int, val y: Int) + +fun neighbors(width: Int, height: Int, c: Coordinate) = sequence { + val x = c.x + val y = c.y + if (x > 0) yield(Coordinate(x - 1, y)) + if (y + 1 < height) yield(Coordinate(x, y + 1)) + if (x + 1 < width) yield(Coordinate(x + 1, y)) + if (y > 0) yield(Coordinate(x, y - 1)) +} + diff --git a/src/main/kotlin/me/gergo/math.kt b/src/main/kotlin/me/gergo/math.kt new file mode 100644 index 0000000..ad7e266 --- /dev/null +++ b/src/main/kotlin/me/gergo/math.kt @@ -0,0 +1,14 @@ +package me.gergo + +fun lcm(a: Int, b: Int) = a * (b / gcd(a, b)) + +fun gcd(a: Int, b: Int): Int { + var a0 = a + var b0 = b + while (b0 > 0) { + val temp = b0 + b0 = a0 % b0 + a0 = temp + } + return a0 +} diff --git a/src/main/kotlin/me/gergo/search.kt b/src/main/kotlin/me/gergo/search.kt new file mode 100644 index 0000000..26ca783 --- /dev/null +++ b/src/main/kotlin/me/gergo/search.kt @@ -0,0 +1,44 @@ +package me.gergo + +fun aStar( + start: N, goal: N, + neighborFn: (N) -> Sequence, + heuristicFn: (N) -> Double, + distanceFn: (N, N) -> Double +): List { + val openSet = mutableSetOf(start) + val cameFrom = mutableMapOf() + + val gScore = mutableMapOf() + gScore[start] = 0.0 + + val fScore = mutableMapOf() + fScore[start] = heuristicFn(start) + + while (openSet.isNotEmpty()) { + val current = openSet.minBy { fScore.getOrDefault(it, Double.POSITIVE_INFINITY) } + if (current == goal) { + // Path found, reconstructing + val result = mutableListOf(current) + var c: N? = current + while (true) { + c = cameFrom[c] + if (c == null) break + result.add(0, c) + } + return result + } + + openSet.remove(current) + for (neighbor in neighborFn(current)) { + val tentativeGScore = gScore.getOrDefault(current, Double.POSITIVE_INFINITY) + distanceFn(current, neighbor) + if (tentativeGScore < gScore.getOrDefault(neighbor, Double.POSITIVE_INFINITY)) { + cameFrom[neighbor] = current + gScore[neighbor] = tentativeGScore + fScore[neighbor] = tentativeGScore + heuristicFn(neighbor) + openSet.add(neighbor) + } + } + } + return emptyList() // Path not found +}