Skip to content

Commit

Permalink
Day 1: Trebuchet?!
Browse files Browse the repository at this point in the history
  • Loading branch information
ephemient committed Dec 1, 2023
1 parent e4ac4a0 commit 26370e6
Show file tree
Hide file tree
Showing 28 changed files with 830 additions and 3 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@

Development occurs in language-specific directories:

|[Haskell](hs) ![Haskell CI](https://github.com/ephemient/aoc2023/workflows/Haskell%20CI/badge.svg)|
|--:|
|[Day1.hs](hs/src/Day1.hs)|
|[Haskell](hs) ![Haskell CI](https://github.com/ephemient/aoc2023/workflows/Haskell%20CI/badge.svg)|[Kotlin](kt)|
|--:|--:|
|[Day1.hs](hs/src/Day1.hs)|[Day1.kt](kt/aoc2023-lib/src/commonMain/kotlin/com/github/ephemient/aoc2023/Day1.kt)|
5 changes: 5 additions & 0 deletions kt/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.gradle/
.idea/
build/
local.properties
*~
34 changes: 34 additions & 0 deletions kt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# [Advent of Code 2023](https://adventofcode.com/2023)
### my answers in [Kotlin](https://www.kotlinlang.org/)

This project builds with [Gradle](https://gradle.org/).

Run the test suite:

```sh
./gradlew :aoc2023-lib:allTests
```

Run [kotlinx.benchmark](https://github.com/Kotlin/kotlinx-benchmark) ([JMH](https://openjdk.java.net/projects/code-tools/jmh/)) benchmarks:

```sh
./gradlew :aoc2023-exe:benchmark
```

Print solutions for the inputs provided in local data files:

```sh
./gradlew :aoc2023-exe:jvmRun :aoc2023-exe:run{Debug,Release}Executable{LinuxX64,Macos{X64,Arm64},MingwX64}
```

Run all checks, including [Detekt](https://detekt.github.io/) static code analysis and [ktlint](https://ktlint.github.io/) formatter:

```sh
./gradlew check
```

Check for newer versions of dependencies:

```sh
./gradlew :dependencyUpdates
```
65 changes: 65 additions & 0 deletions kt/aoc2023-exe/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget

plugins {
application
kotlin("multiplatform")
kotlin("plugin.allopen")
alias(libs.plugins.kotlinx.benchmark)
id("com.github.ephemient.aoc2023.detekt")
id("com.github.ephemient.aoc2023.kotlin.multiplatform.jvm.platform")
id("com.github.ephemient.aoc2023.kotlin.multiplatform.native.platforms")
}

application {
mainClass = "com.github.ephemient.aoc2023.exe.Main"
}

kotlin {
jvm {
withJava()
}

targets.withType<KotlinJvmTarget> {
mainRun {
mainClass = application.mainClass
}
}

targets.withType<KotlinNativeTarget> {
binaries.executable {
entryPoint = "com.github.ephemient.aoc2023.exe.main"
}
}

sourceSets {
commonMain {
dependencies {
implementation(projects.aoc2023Lib)
implementation(libs.kotlinx.coroutines)
}
}

commonTest {
dependencies {
implementation(libs.kotlinx.benchmark)
}
}

nativeMain {
dependencies {
implementation(libs.okio)
}
}
}
}

allOpen {
annotation("org.openjdk.jmh.annotations.State")
}

benchmark {
targets {
register("jvmTest")
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package com.github.ephemient.aoc2023.exe

import com.github.ephemient.aoc2023.days
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

internal suspend fun mainImpl(vararg args: String): Unit = withContext(Dispatchers.Default) {
for (day in days) {
if (args.isNotEmpty() && day.name !in args) continue
println("Day ${day.name}")
for (part in day.solver(getDayInput(day.day))) println(part())
println()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package com.github.ephemient.aoc2023.exe

internal expect suspend fun getDayInput(day: Int): String
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package com.github.ephemient.aoc2023.exe

import com.github.ephemient.aoc2023.Day1
import kotlinx.benchmark.Benchmark
import kotlinx.benchmark.Scope
import kotlinx.benchmark.Setup
import kotlinx.benchmark.State
import kotlinx.coroutines.runBlocking

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

@Setup
fun setup() {
input = runBlocking {
getDayInput(1)
}
}

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

@Benchmark
fun part2() = Day1(input).part2()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.github.ephemient.aoc2023.exe

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.File

@Suppress("InjectDispatcher")
internal actual suspend fun getDayInput(day: Int): String = withContext(Dispatchers.IO) {
File(System.getenv("AOC2023_DATADIR")?.ifEmpty { null } ?: ".", "day$day.txt").readText()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
@file:JvmName("Main")

package com.github.ephemient.aoc2023.exe

suspend fun main(vararg args: String): Unit = mainImpl(*args)
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.github.ephemient.aoc2023.exe

import kotlinx.cinterop.ExperimentalForeignApi
import kotlinx.cinterop.toKString
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
import kotlinx.coroutines.withContext
import okio.Path.Companion.toPath
import okio.buffer
import platform.posix.getenv

@OptIn(ExperimentalForeignApi::class)
internal actual suspend fun getDayInput(day: Int): String = withContext(Dispatchers.IO) {
val dataDir = (getenv("AOC2023_DATADIR")?.toKString()?.ifEmpty { null } ?: ".").toPath()
okio.FileSystem.SYSTEM.source(dataDir / "day$day.txt").buffer().readUtf8()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.ephemient.aoc2023.exe

import kotlinx.coroutines.runBlocking

fun main(vararg args: String): Unit = runBlocking {
mainImpl(*args)
}
29 changes: 29 additions & 0 deletions kt/aoc2023-lib/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
plugins {
kotlin("multiplatform")
id("com.github.ephemient.aoc2023.detekt")
id("com.github.ephemient.aoc2023.kotlin.multiplatform.jvm.platform")
id("com.github.ephemient.aoc2023.kotlin.multiplatform.native.platforms")
}

kotlin {
sourceSets {
commonTest {
dependencies {
implementation(kotlin("test"))
implementation(libs.kotlinx.coroutines.test)
}
}

jvmTest {
dependencies {
implementation(kotlin("test-junit5"))
implementation(libs.junit.jupiter.api)
runtimeOnly(libs.junit.jupiter.engine)
}
}
}
}

tasks.jvmTest {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.github.ephemient.aoc2023

class Day1(input: String) {
private val lines = input.lines()

fun part1() = solve(digits)

fun part2() = solve(extendedDigits)

private fun solve(values: Collection<IndexedValue<String>>): Int = lines.sumOf { line ->
val subset = values.filter { it.value in line }
if (subset.isNotEmpty()) {
10 * subset.minBy { line.indexOf(it.value) }.index + subset.maxBy { line.lastIndexOf(it.value) }.index
} else {
0
}
}

companion object {
private val digits = List(10) { IndexedValue(it, it.toString()) }
private val extendedDigits = digits + listOf(
IndexedValue(1, "one"),
IndexedValue(2, "two"),
IndexedValue(3, "three"),
IndexedValue(4, "four"),
IndexedValue(5, "five"),
IndexedValue(6, "six"),
IndexedValue(7, "seven"),
IndexedValue(8, "eight"),
IndexedValue(9, "nine"),
)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.github.ephemient.aoc2023

val days = listOf(
Day(1) { with(Day1(it)) { listOf({ part1() }, { part2() }) } },
)

data class Day(
val day: Int,
val name: String = day.toString(),
val solver: (String) -> List<suspend () -> Any?>,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.github.ephemient.aoc2023

import kotlinx.coroutines.test.runTest
import kotlin.test.Test
import kotlin.test.assertEquals

class Day1Test {
@Test
fun part1() = runTest {
assertEquals(142, Day1(example1).part1())
}

@Test
fun part2() = runTest {
assertEquals(281, Day1(example2).part2())
}

companion object {
private val example1 =
"""
|1abc2
|pqr3stu8vwx
|a1b2c3d4e5f
|treb7uchet
|""".trimMargin()

private val example2 =
"""
|two1nine
|eightwothree
|abcone2threexyz
|xtwone3four
|4nineeightseven2
|zoneight234
|7pqrstsixteen
|""".trimMargin()
}
}
15 changes: 15 additions & 0 deletions kt/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
plugins {
alias(libs.plugins.kotlin.plugin.allopen) apply false
alias(libs.plugins.kotlinx.benchmark) apply false
alias(libs.plugins.dependency.updates)
id("com.github.ephemient.aoc2023.detekt")
}

tasks.detekt {
setSource(files().apply { from(layout.projectDirectory.asFileTree.matching { include("*.kts") }) })
}

tasks.dependencyUpdates {
revision = "release"
gradleReleaseChannel = "current"
}
27 changes: 27 additions & 0 deletions kt/buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
plugins {
`kotlin-dsl`
}

group = "com.github.ephemient.aoc2023.build-logic"

gradlePlugin {
plugins {
create("KotlinMultiplatformDefaultHierarchyPlugin") {
id = "com.github.ephemient.aoc2023.kotlin.multiplatform.base"
implementationClass = "com.github.ephemient.aoc2023.buildsrc.KotlinMultiplatformBasePlugin"
}
create("KotlinMultiplatformJvmPlatformPlugin") {
id = "com.github.ephemient.aoc2023.kotlin.multiplatform.jvm.platform"
implementationClass = "com.github.ephemient.aoc2023.buildsrc.KotlinMultiplatformJvmPlatformPlugin"
}
create("KotlinMultiplatformNativePlatformsPlugin") {
id = "com.github.ephemient.aoc2023.kotlin.multiplatform.native.platforms"
implementationClass = "com.github.ephemient.aoc2023.buildsrc.KotlinMultiplatformNativePlatformsPlugin"
}
}
}

dependencies {
implementation(kotlin("gradle-plugin", libs.versions.kotlin.get()))
implementation(libs.detekt.plugin)
}
20 changes: 20 additions & 0 deletions kt/buildSrc/settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
}
}

dependencyResolutionManagement {
repositories {
mavenCentral()
}

versionCatalogs {
create("libs") {
from(files("../gradle/libs.versions.toml"))
}
}
}

rootProject.name = "buildSrc"
Loading

0 comments on commit 26370e6

Please sign in to comment.