From 9f1a76faa7ce090e3ff21deab5d85ce0d0b69b48 Mon Sep 17 00:00:00 2001 From: Daniel Lin Date: Fri, 6 Dec 2024 02:00:47 -0500 Subject: [PATCH] Day 6: Guard Gallivant --- README.md | 2 +- kt/aoc2024-exe/build.gradle.kts | 12 +++-- .../github/ephemient/aoc2024/exe/Day6Bench.kt | 35 +++++++++++++ .../github/ephemient/aoc2024/exe/Day6Bench.kt | 20 ++++++++ .../com/github/ephemient/aoc2024/Day6.kt | 51 +++++++++++++++++++ .../com/github/ephemient/aoc2024/Days.kt | 1 + .../com/github/ephemient/aoc2024/Day6Test.kt | 33 ++++++++++++ 7 files changed, 150 insertions(+), 4 deletions(-) create mode 100644 kt/aoc2024-exe/src/blockingBench/kotlin/com/github/ephemient/aoc2024/exe/Day6Bench.kt create mode 100644 kt/aoc2024-exe/src/nonblockingBench/kotlin/com/github/ephemient/aoc2024/exe/Day6Bench.kt create mode 100644 kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day6.kt create mode 100644 kt/aoc2024-lib/src/commonTest/kotlin/com/github/ephemient/aoc2024/Day6Test.kt diff --git a/README.md b/README.md index 4924009..5566055 100644 --- a/README.md +++ b/README.md @@ -10,4 +10,4 @@ Development occurs in language-specific directories: |[Day3.hs](hs/src/Day3.hs)|[Day3.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day3.kt)|[day3.py](py/aoc2024/day3.py)|[day3.rs](rs/src/day3.rs)| |[Day4.hs](hs/src/Day4.hs)|[Day4.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day4.kt)|[day4.py](py/aoc2024/day4.py)|[day4.rs](rs/src/day4.rs)| |[Day5.hs](hs/src/Day5.hs)|[Day5.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day5.kt)|[day5.py](py/aoc2024/day5.py)|[day5.rs](rs/src/day5.rs)| -|[Day6.hs](hs/src/Day6.hs)|||| +|[Day6.hs](hs/src/Day6.hs)|[Day6.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day6.kt)||| diff --git a/kt/aoc2024-exe/build.gradle.kts b/kt/aoc2024-exe/build.gradle.kts index a7601d9..811c162 100644 --- a/kt/aoc2024-exe/build.gradle.kts +++ b/kt/aoc2024-exe/build.gradle.kts @@ -37,9 +37,15 @@ kotlin { applyHierarchyTemplate { withSourceSetTree(KotlinSourceSetTree("bench")) common { - withJvm() - withWasmJs() - withNative() + group("blocking") { + withJvm() + group("native") { + withNative() + } + } + group("nonblocking") { + withWasmJs() + } } } diff --git a/kt/aoc2024-exe/src/blockingBench/kotlin/com/github/ephemient/aoc2024/exe/Day6Bench.kt b/kt/aoc2024-exe/src/blockingBench/kotlin/com/github/ephemient/aoc2024/exe/Day6Bench.kt new file mode 100644 index 0000000..23485c0 --- /dev/null +++ b/kt/aoc2024-exe/src/blockingBench/kotlin/com/github/ephemient/aoc2024/exe/Day6Bench.kt @@ -0,0 +1,35 @@ +package com.github.ephemient.aoc2024.exe + +import com.github.ephemient.aoc2024.Day6 +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.Setup +import kotlinx.benchmark.State +import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.runBlocking + +@State(Scope.Benchmark) +class Day6Bench { + private lateinit var input: String + + @Setup + fun setup() { + input = getDayInput(6) + } + + @Benchmark + fun part1() = Day6(input).part1() + + @Benchmark + fun part2() = runBlocking(Dispatchers.Default) { + Day6(input).part2() + } + + @Benchmark + fun both(bh: Blackhole) = runBlocking(Dispatchers.Default) { + val day6 = Day6(input) + bh.consume(day6.part1()) + bh.consume(day6.part2()) + } +} diff --git a/kt/aoc2024-exe/src/nonblockingBench/kotlin/com/github/ephemient/aoc2024/exe/Day6Bench.kt b/kt/aoc2024-exe/src/nonblockingBench/kotlin/com/github/ephemient/aoc2024/exe/Day6Bench.kt new file mode 100644 index 0000000..e3447d5 --- /dev/null +++ b/kt/aoc2024-exe/src/nonblockingBench/kotlin/com/github/ephemient/aoc2024/exe/Day6Bench.kt @@ -0,0 +1,20 @@ +package com.github.ephemient.aoc2024.exe + +import com.github.ephemient.aoc2024.Day6 +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Scope +import kotlinx.benchmark.Setup +import kotlinx.benchmark.State + +@State(Scope.Benchmark) +class Day6Bench { + private lateinit var input: String + + @Setup + fun setup() { + input = getDayInput(6) + } + + @Benchmark + fun part1() = Day6(input).part1() +} diff --git a/kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day6.kt b/kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day6.kt new file mode 100644 index 0000000..e210055 --- /dev/null +++ b/kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day6.kt @@ -0,0 +1,51 @@ +package com.github.ephemient.aoc2024 + +import kotlinx.coroutines.ExperimentalCoroutinesApi +import kotlinx.coroutines.flow.asFlow +import kotlinx.coroutines.flow.count +import kotlinx.coroutines.flow.filter +import kotlinx.coroutines.flow.flatMapMerge +import kotlinx.coroutines.flow.flowOf + +class Day6(input: String) { + private val lines = input.lines() + private val initialPosition = lines.withIndex().firstNotNullOf { (y, line) -> + val x = line.indexOf('^') + if (x >= 0) y to x else null + } + + fun part1() = lines.walk(initialPosition).mapTo(mutableSetOf()) { it.first }.size + + @OptIn(ExperimentalCoroutinesApi::class) + suspend fun part2() = lines.walk(initialPosition) + .mapTo(mutableSetOf()) { it.first } + .apply { remove(initialPosition) } + .asFlow() + .flatMapMerge { (y, x) -> + val lines = lines.toMutableList() + lines[y] = StringBuilder(lines[y]).apply { set(x, '#') }.toString() + flowOf(Unit).filter { !lines.walk(initialPosition).all(mutableSetOf()::add) } + } + .count() + + companion object { + private fun List.walk(position: IntPair) = sequence { + var (y, x) = position + var dy = -1 + var dx = 0 + while (true) { + yield(Pair(y to x, dy to dx)) + val nextY = y + dy + val nextX = x + dx + when (getOrNull(nextY)?.getOrNull(nextX)) { + null -> break + '#' -> dy = dx.also { dx = -dy } + else -> { + y = nextY + x = nextX + } + } + } + } + } +} diff --git a/kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Days.kt b/kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Days.kt index f533a7f..befda2d 100644 --- a/kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Days.kt +++ b/kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Days.kt @@ -6,6 +6,7 @@ val days: List = listOf( Day(3, ::Day3, Day3::part1, Day3::part2), Day(4, ::Day4, Day4::part1, Day4::part2), Day(5, ::Day5, Day5::part1, Day5::part2), + Day(6, ::Day6, Day6::part1, Day6::part2), ) data class Day( diff --git a/kt/aoc2024-lib/src/commonTest/kotlin/com/github/ephemient/aoc2024/Day6Test.kt b/kt/aoc2024-lib/src/commonTest/kotlin/com/github/ephemient/aoc2024/Day6Test.kt new file mode 100644 index 0000000..37826ba --- /dev/null +++ b/kt/aoc2024-lib/src/commonTest/kotlin/com/github/ephemient/aoc2024/Day6Test.kt @@ -0,0 +1,33 @@ +package com.github.ephemient.aoc2024 + +import kotlinx.coroutines.test.runTest +import kotlin.test.Test +import kotlin.test.assertEquals + +class Day6Test { + @Test + fun part1() { + assertEquals(41, Day6(example).part1()) + } + + @Test + fun part2() = runTest{ + assertEquals(6, Day6(example).part2()) + } + + companion object { + private val example = + """ + |....#..... + |.........# + |.......... + |..#....... + |.......#.. + |.......... + |.#..^..... + |........#. + |#......... + |......#... + |""".trimMargin() + } +}