Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Day 1: Historian Hysteria #3

Merged
merged 1 commit into from
Dec 1, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# generated by Gradle Wrapper
kt/gradlew linguist-generated
kt/gradlew.bat linguist-generated
39 changes: 39 additions & 0 deletions .github/workflows/kt.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
name: Kotlin CI

on:
push:
branches: [ main ]
paths: [ kt/** ]
pull_request:
branches: [ main ]
paths: [ kt/** ]

workflow_dispatch:

jobs:
get-inputs:
uses: ephemient/aoc2024/.github/workflows/get-inputs.yml@main
secrets:
SESSION: ${{ secrets.SESSION }}

build:
needs: [ get-inputs ]
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v4
- uses: actions/download-artifact@v4
with:
name: inputs
path: inputs
- uses: actions/setup-java@v4
with:
distribution: temurin
java-version: 21
- uses: gradle/actions/setup-gradle@v4
- run: ./gradlew check
working-directory: kt
- run: ./gradlew :aoc2024-exe:jvmRun
working-directory: kt
env:
AOC2024_DATADIR: ${{ github.workspace }}/inputs
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/aoc2024/workflows/Haskell%20CI/badge.svg)|
|--:|
|[Day1.hs](hs/src/Day1.hs)|
|[Haskell](hs) ![Haskell CI](https://github.com/ephemient/aoc2024/workflows/Haskell%20CI/badge.svg)|[Kotlin](kt) ![Kotlin CI](https://github.com/ephemient/aoc2024/workflows/Kotlin%20CI/badge.svg)|
|--:|--:|
|[Day1.hs](hs/src/Day1.hs)|[Day1.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day1.kt)|
1 change: 1 addition & 0 deletions kt/.envrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export AOC2024_DATADIR=$(realpath ..)
6 changes: 6 additions & 0 deletions kt/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
.gradle/
.kotlin/
.idea/
build/
local.properties
*~
22 changes: 22 additions & 0 deletions kt/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# [Advent of Code 2024](https://adventofcode.com/2024)
### my answers in [Kotlin](https://www.kotlinlang.org/) ![Kotlin CI](https://github.com/ephemient/aoc2024/workflows/Kotlin%20CI/badge.svg)

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

Run the test suite:

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

Print solutions for the inputs provided in local data files:

```sh
./gradlew :aoc2024-exe:jvmRun
```

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

```sh
./gradlew check
```
27 changes: 27 additions & 0 deletions kt/aoc2024-exe/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import io.gitlab.arturbosch.detekt.Detekt

plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.detekt)
}

kotlin {
jvm {
mainRun {
mainClass = "com.github.ephemient.aoc2024.exe.Main"
}
}

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

dependencies {
detektPlugins(libs.bundles.detekt.plugins)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package com.github.ephemient.aoc2024.exe

import com.github.ephemient.aoc2024.days

internal suspend fun mainImpl(args: Array<out String>) {
for (day in days) {
if ((args.isNotEmpty() || day.skipByDefault) && 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.aoc2024.exe

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

import java.io.File

internal actual fun getDayInput(day: Int): String =
File(System.getenv("AOC2024_DATADIR")?.ifEmpty { null } ?: ".", "day$day.txt").readText()
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
@file:JvmName("Main")

package com.github.ephemient.aoc2024.exe

import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext

@Suppress("InjectDispatcher")
suspend fun main(vararg args: String): Unit = withContext(Dispatchers.Default) {
mainImpl(args)
}
39 changes: 39 additions & 0 deletions kt/aoc2024-lib/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
plugins {
alias(libs.plugins.kotlin.multiplatform)
alias(libs.plugins.detekt)
}

kotlin {
jvm()

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

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

dependencies {
detektPlugins(libs.bundles.detekt.plugins)
}

tasks.withType<Test>().configureEach {
useJUnitPlatform()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.github.ephemient.aoc2024

import kotlin.math.abs

class Day1(input: String) {
private val left: List<Int>
private val right: List<Int>

init {
val left = mutableListOf<Int>()
val right = mutableListOf<Int>()
for (line in input.lineSequence()) {
val parts = line.trim().split(splitter, limit = 2)
val x = parts.getOrNull(0)?.toIntOrNull() ?: continue
val y = parts.getOrNull(1)?.toIntOrNull() ?: continue
left.add(x)
right.add(y)
}
this.left = left.toList()
this.right = right.toList()
}

fun part1() = left.sorted().zip(right.sorted(), Int::minus).sumOf(::abs)

fun part2(): Int {
val right = right.groupingBy { it }.eachCount()
return left.sumOf { it * right.getOrElse(it) { 0 } }
}

companion object {
private val splitter = """\s+""".toRegex()
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package com.github.ephemient.aoc2024

val days: List<Day> = listOf(
Day(1, ::Day1, Day1::part1, Day1::part2),
)

data class Day(
val day: Int,
val parts: Int,
val solver: (String) -> List<suspend () -> Any?>,
val name: String = day.toString(),
val skipByDefault: Boolean = false,
)

fun <T> Day(
day: Int,
create: (String) -> T,
vararg parts: suspend (T) -> Any?,
name: String = day.toString(),
skipByDefault: Boolean = false,
): Day = Day(
day = day,
parts = parts.size,
solver = { with(create(it)) { parts.map { suspend { it.invoke(this) } } } },
name = name,
skipByDefault = skipByDefault,
)
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package com.github.ephemient.aoc2024

data class IntPair(val first: Int, val second: Int) {
override fun toString(): String = "($first, $second)"
}

infix fun Int.to(other: Int): IntPair = IntPair(this, other)
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
package com.github.ephemient.aoc2024

fun gcd(x: Long, y: Long): Long {
var a = x
var b = y
while (b != 0L) a = b.also { b = a.mod(b) }
return a
}

fun lcm(x: Long, y: Long): Long = x / gcd(x, y) * y
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.github.ephemient.aoc2024

import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.fold
import kotlinx.coroutines.launch

suspend fun <T> Iterable<T>.parSum(block: (T) -> Long): Long = channelFlow {
for (value in this@parSum) {
launch {
send(block(value))
}
}
}.fold(0, Long::plus)
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package com.github.ephemient.aoc2024

fun Iterable<String>.transpose(): List<String> = buildList {
val strings = [email protected](mutableListOf()) { it.isNotEmpty() }
var i = 0
while (strings.isNotEmpty()) {
add(buildString(strings.size) { for (string in strings) append(string[i]) })
i++
strings.removeAll { it.length == i }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package com.github.ephemient.aoc2024

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

class Day1Test {
@Test
fun part1() {
assertEquals(11, Day1(example).part1())
}

@Test
fun part2() {
assertEquals(31, Day1(example).part2())
}

companion object {
private val example =
"""
|3 4
|4 3
|2 5
|1 3
|3 9
|3 3
|""".trimMargin()
}
}
5 changes: 5 additions & 0 deletions kt/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
plugins {
alias(libs.plugins.kotlin.multiplatform) apply false
}

group = "com.github.ephemient.aoc2024"
5 changes: 5 additions & 0 deletions kt/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
kotlin.code.style=official
org.gradle.caching=true
org.gradle.configuration-cache=true
org.gradle.jvmargs=-Xmx512m -XX:+UseParallelGC
org.gradle.parallel=true
21 changes: 21 additions & 0 deletions kt/gradle/libs.versions.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[versions]
detekt = "1.23.7"
junit-jupiter = "5.11.3"
kotlin = "2.1.0"
kotlinx-benchmark = "0.4.13"
kotlinx-coroutines = "1.9.0"
okio = "3.9.1"

[plugins]
detekt = { id = "io.gitlab.arturbosch.detekt", version.ref = "detekt" }
kotlin-multiplatform = { id = "org.jetbrains.kotlin.multiplatform", version.ref = "kotlin" }

[libraries]
detekt-formatting = { module = "io.gitlab.arturbosch.detekt:detekt-formatting", version.ref = "detekt" }
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" }
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" }

[bundles]
detekt-plugins = ["detekt-formatting"]
Binary file added kt/gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
7 changes: 7 additions & 0 deletions kt/gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.11.1-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
Loading