Skip to content

Commit

Permalink
Merge pull request #138 from ephemient/kt/day21
Browse files Browse the repository at this point in the history
  • Loading branch information
ephemient authored Dec 21, 2024
2 parents 18cebdb + 75d67af commit d43eb7f
Show file tree
Hide file tree
Showing 8 changed files with 230 additions and 2 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,4 @@ Development occurs in language-specific directories:
|[Day18.hs](hs/src/Day18.hs)|[Day18.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day18.kt)|[day18.py](py/aoc2024/day18.py)|[day18.rs](rs/src/day18.rs)|
|[Day19.hs](hs/src/Day19.hs)|[Day19.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day19.kt)|[day19.py](py/aoc2024/day19.py)|[day19.rs](rs/src/day19.rs)|
|[Day20.hs](hs/src/Day20.hs)|[Day20.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day20.kt)|[day20.py](py/aoc2024/day20.py)|[day20.rs](rs/src/day20.rs)|
|[Day21.hs](hs/src/Day21.hs)||||
|[Day21.hs](hs/src/Day21.hs)|[Day21.kt](kt/aoc2024-lib/src/jvmCodegen/kotlin/com/github/ephemient/aoc2024/codegen/Day21.kt)|||
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.github.ephemient.aoc2024.exe

import com.github.ephemient.aoc2024.Day21
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Blackhole
import kotlinx.benchmark.Scope
import kotlinx.benchmark.Setup
import kotlinx.benchmark.State

@State(Scope.Benchmark)
class Day21Bench {
private lateinit var input: String

@Setup
fun setup() {
input = getDayInput(21)
}

@Benchmark
fun part1() = Day21(input).part1()

@Benchmark
fun part2() = Day21(input).part2()

@Benchmark
fun solve(bh: Blackhole) {
val day21 = Day21(input)
bh.consume(day21.part1())
bh.consume(day21.part2())
}
}
17 changes: 16 additions & 1 deletion kt/aoc2024-lib/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,16 @@ plugins {
}

kotlin {
jvm()
jvm {
val codegen by compilations.creating
val runCodegen by tasks.registering(JavaExec::class) {
mainClass = "com.github.ephemient.aoc2024.codegen.Main"
classpath(codegen.output.allOutputs, codegen.runtimeDependencyFiles)
outputs.dir(layout.buildDirectory.dir("build/sources/codegen"))
argumentProviders.add { listOf(outputs.files.singleFile.path) }
}
kotlin.sourceSets.getByName("commonMain").kotlin.srcDirs(runCodegen)
}
wasmJs {
browser()
nodejs()
Expand Down Expand Up @@ -54,6 +63,12 @@ kotlin {
runtimeOnly(libs.junit.jupiter.engine)
}
}

getByName("jvmCodegen") {
dependencies {
implementation(libs.kotlinpoet)
}
}
}

val detektTaskNames = targets.flatMap { target ->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ val days: List<Day> = listOf(
Day(18, ::Day18, Day18::part1, Day18::part2),
Day(19, ::Day19, Day19::solve),
Day(20, ::Day20, Day20::part1, Day20::part2),
Day(21, ::Day21, Day21::part1, Day21::part2),
)

data class Day(
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package com.github.ephemient.aoc2024

import kotlin.test.Test
import kotlin.test.assertEquals

class Day21Test {
@Test
fun part1() {
assertEquals(126384, Day21(example).part1())
}

companion object {
private val example =
"""
|029A
|980A
|179A
|456A
|379A
|""".trimMargin()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
package com.github.ephemient.aoc2024.codegen

import com.squareup.kotlinpoet.ClassName
import com.squareup.kotlinpoet.CodeBlock
import com.squareup.kotlinpoet.FileSpec
import com.squareup.kotlinpoet.FunSpec
import com.squareup.kotlinpoet.KModifier
import com.squareup.kotlinpoet.LIST
import com.squareup.kotlinpoet.LONG
import com.squareup.kotlinpoet.LONG_ARRAY
import com.squareup.kotlinpoet.MemberName
import com.squareup.kotlinpoet.MemberName.Companion.member
import com.squareup.kotlinpoet.ParameterizedTypeName.Companion.parameterizedBy
import com.squareup.kotlinpoet.PropertySpec
import com.squareup.kotlinpoet.STRING
import com.squareup.kotlinpoet.TypeSpec
import com.squareup.kotlinpoet.joinToCode
import java.nio.file.Path
import kotlin.math.abs

fun day21(outputDir: Path, className: ClassName = ClassName("com.github.ephemient.aoc2024", "Day21")) {
FileSpec.builder(className)
.addType(
TypeSpec.classBuilder(className)
.primaryConstructor(
FunSpec.constructorBuilder()
.addParameter("input", STRING)
.build()
)
.addProperty(
PropertySpec.builder("lines", LIST.parameterizedBy(STRING))
.addModifiers(KModifier.PRIVATE)
.initializer("%N.%M()", "input", MemberName("kotlin.text", "lines"))
.build()
)
.addFunctions(
arrayOf(IndexedValue(2, "part1"), IndexedValue(25, "part2")).map { (depth, name) ->
FunSpec.builder(name)
.returns(LONG)
.beginControlFlow("return %N.%M", "lines", MemberName("kotlin.collections", "sumOf"))
.addStatement("var %N = 10", "i")
.addStatement("var %N = 0", "numeric")
.addStatement("var %N = 0L", "length")
.beginControlFlow("for (%N in %N)", "char", "it")
.beginControlFlow("val %N = when (%N)", "j", "char")
.beginControlFlow("in '0'..'9' ->")
.addStatement("%1N = 10 * %1N + (%2N - '0')", "numeric", "char")
.addStatement("%N - '0'", "char")
.endControlFlow()
.addStatement("else -> 10")
.endControlFlow()
.addStatement(
"%N += %M[11 * %N + %N]",
"length",
className.nestedClass("Companion").member(name),
"i",
"j",
)
.addStatement("%N = %N", "i", "j")
.endControlFlow()
.addStatement("%N * %N", "numeric", "length")
.endControlFlow()
.build()
}
)
.addType(
TypeSpec.companionObjectBuilder()
.addProperty(
PropertySpec.builder("part1", LONG_ARRAY)
.addModifiers(KModifier.PRIVATE)
.initializer(
"%M(%L)",
MemberName("kotlin", "longArrayOf"),
lut(2).joinToCode(",♢") { CodeBlock.of("%L", it) },
)
.build()
)
.addProperty(
PropertySpec.builder("part2", LONG_ARRAY)
.addModifiers(KModifier.PRIVATE)
.initializer(
"%M(%L)",
MemberName("kotlin", "longArrayOf"),
lut(25).joinToCode(",♢") { CodeBlock.of("%L", it) },
)
.build()
)
.build()
)
.build()
)
.build()
.writeTo(outputDir)
}

private val keypad = intArrayOf(
3 * 1 + 1, // 0
3 * 2 + 0, // 1
3 * 2 + 1, // 2
3 * 2 + 2, // 3
3 * 3 + 0, // 4
3 * 3 + 1, // 5
3 * 3 + 2, // 6
3 * 4 + 0, // 7
3 * 4 + 1, // 8
3 * 4 + 2, // 9
3 * 1 + 2, // A
)
private const val BLANK = 3 * 1 + 0
private const val UP = 3 * 1 + 1
private const val A = 3 * 1 + 2
private const val LEFT = 3 * 0 + 0
private const val DOWN = 3 * 0 + 1
private const val RIGHT = 3 * 0 + 2

private fun lut(depth: Int): List<Long> {
var lut = Array(15 * 15) {
val p1 = it / 15
val p2 = it % 15
if (p1 == BLANK || p2 == BLANK) null else abs(p2 / 3 - p1 / 3) + abs(p2 % 3 - p1 % 3) + 1L
}
fun best(p1: Int, p2: Int, pos: Int): Long? {
if (p1 == BLANK || p2 == BLANK) return null
if (p1 == p2) return lut[15 * pos + A]
val v = when {
p1 / 3 < p2 / 3 -> lut[15 * pos + UP]?.let { best(p1 + 3, p2, UP)?.let(it::plus) }
p1 / 3 > p2 / 3 -> lut[15 * pos + DOWN]?.let { best(p1 - 3, p2, DOWN)?.let(it::plus) }
else -> null
}
val h = when {
p1 % 3 < p2 % 3 -> lut[15 * pos + RIGHT]?.let { best(p1 + 1, p2, RIGHT)?.let(it::plus) }
p1 % 3 > p2 % 3 -> lut[15 * pos + LEFT]?.let { best(p1 - 1, p2, LEFT)?.let(it::plus) }
else -> null
}
return if (v != null && h != null) minOf(v, h) else v ?: h
}
repeat(depth) { lut = Array(15 * 15) { best(it / 15, it % 15, A) } }
return List(11 * 11) { lut[15 * keypad[it / 11] + keypad[it % 11]]!! }.also {
println(it.chunked(11).joinToString(",\n", "Day21[$depth] = [\n", "]") { it.joinToString() })
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
@file:JvmName("Main")

package com.github.ephemient.aoc2024.codegen

import java.nio.file.Files
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.Path
import kotlin.io.path.deleteRecursively

@OptIn(ExperimentalPathApi::class)
fun main(argv: Array<String>) {
val outputDir = Path(argv.single())
outputDir.deleteRecursively()
Files.createDirectory(outputDir)
day21(outputDir)
}
2 changes: 2 additions & 0 deletions kt/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ junit-jupiter = "5.11.4"
kotlin = "2.1.0"
kotlinx-benchmark = "0.4.13"
kotlinx-coroutines = "1.10.1"
kotlinpoet = "2.0.0"
native-image = "0.10.4"
okio = "3.9.1"

Expand All @@ -19,6 +20,7 @@ detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting",
junit-jupiter-api = { module = "org.junit.jupiter:junit-jupiter-api", version.ref = "junit-jupiter" }
junit-jupiter-engine = { module = "org.junit.jupiter:junit-jupiter-engine", version.ref = "junit-jupiter" }
kotlin-wrappers-node = { module = "org.jetbrains.kotlin-wrappers:kotlin-node", version = "22.5.5-pre.854" }
kotlinpoet = { module = "com.squareup:kotlinpoet", version.ref = "kotlinpoet" }
kotlinx-benchmark = { module = "org.jetbrains.kotlinx:kotlinx-benchmark-runtime", version.ref = "kotlinx-benchmark" }
kotlinx-coroutines = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-core", version.ref = "kotlinx-coroutines" }
kotlinx-coroutines-test = { module = "org.jetbrains.kotlinx:kotlinx-coroutines-test", version.ref = "kotlinx-coroutines" }
Expand Down

0 comments on commit d43eb7f

Please sign in to comment.