From 7c026269e906892b259174c8202ced6bf266821b Mon Sep 17 00:00:00 2001 From: Daniel Lin Date: Mon, 9 Dec 2024 03:15:49 -0500 Subject: [PATCH] Day 9: Disk Defragmenter --- README.md | 2 +- .../github/ephemient/aoc2024/exe/Day9Bench.kt | 31 ++++++++++ .../com/github/ephemient/aoc2024/Day9.kt | 56 +++++++++++++++++++ .../com/github/ephemient/aoc2024/Days.kt | 1 + .../com/github/ephemient/aoc2024/Day9Test.kt | 23 ++++++++ 5 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 kt/aoc2024-exe/src/commonBench/kotlin/com/github/ephemient/aoc2024/exe/Day9Bench.kt create mode 100644 kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day9.kt create mode 100644 kt/aoc2024-lib/src/commonTest/kotlin/com/github/ephemient/aoc2024/Day9Test.kt diff --git a/README.md b/README.md index f1b3c03..ffacf4e 100644 --- a/README.md +++ b/README.md @@ -13,4 +13,4 @@ Development occurs in language-specific directories: |[Day6.hs](hs/src/Day6.hs)|[Day6.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day6.kt)|[day6.py](py/aoc2024/day6.py)|[day6.rs](rs/src/day6.rs)| |[Day7.hs](hs/src/Day7.hs)|[Day7.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day7.kt)|[day7.py](py/aoc2024/day7.py)|[day7.rs](rs/src/day7.rs)| |[Day8.hs](hs/src/Day8.hs)|[Day8.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day8.kt)|[day8.py](py/aoc2024/day8.py)|[day8.rs](rs/src/day8.rs)| -|[Day9.hs](hs/src/Day9.hs)|||| +|[Day9.hs](hs/src/Day9.hs)|[Day9.kt](kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day9.kt)||| diff --git a/kt/aoc2024-exe/src/commonBench/kotlin/com/github/ephemient/aoc2024/exe/Day9Bench.kt b/kt/aoc2024-exe/src/commonBench/kotlin/com/github/ephemient/aoc2024/exe/Day9Bench.kt new file mode 100644 index 0000000..adba349 --- /dev/null +++ b/kt/aoc2024-exe/src/commonBench/kotlin/com/github/ephemient/aoc2024/exe/Day9Bench.kt @@ -0,0 +1,31 @@ +package com.github.ephemient.aoc2024.exe + +import com.github.ephemient.aoc2024.Day9 +import kotlinx.benchmark.Benchmark +import kotlinx.benchmark.Blackhole +import kotlinx.benchmark.Scope +import kotlinx.benchmark.Setup +import kotlinx.benchmark.State + +@State(Scope.Benchmark) +class Day9Bench { + private lateinit var input: String + + @Setup + fun setup() { + input = getDayInput(9) + } + + @Benchmark + fun part1() = Day9(input).part1() + + @Benchmark + fun part2() = Day9(input).part2() + + @Benchmark + fun solve(bh: Blackhole) { + val day9 = Day9(input) + bh.consume(day9.part1()) + bh.consume(day9.part2()) + } +} diff --git a/kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day9.kt b/kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day9.kt new file mode 100644 index 0000000..c0cb289 --- /dev/null +++ b/kt/aoc2024-lib/src/commonMain/kotlin/com/github/ephemient/aoc2024/Day9.kt @@ -0,0 +1,56 @@ +package com.github.ephemient.aoc2024 + +class Day9(input: String) { + private val input = input.mapNotNull { it.digitToIntOrNull() } + + fun part1(): Long { + val chunks = input.toIntArray() + var total = 0L + var i = 0 + var j = chunks.lastIndex + var offset = 0 + while (i <= j) { + if (i % 2 == 0) { + val size = chunks[i] + total += i / 2L * triRange(offset, size) + offset += size + i++ + } else if (j % 2 == 0) { + val free = chunks[i] + val size = chunks[j] + total += j / 2L * triRange(offset, minOf(free, size)) + offset += minOf(free, size) + if (free <= size) i++ else chunks[i] = free - size + if (free >= size) j-- else chunks[j] = size - free + } else { + j-- + } + } + return total + } + + fun part2(): Long { + val files = IntArray((input.size + 1) / 2) { input[2 * it] } + val frees = IntArray(input.size / 2) { input[2 * it + 1] } + val offsets = IntArray(input.size) + for (i in 0..offsets.size - 2) offsets[i + 1] = offsets[i] + input[i] + var total = 0L + outer@for (i in files.lastIndex downTo 0) { + val size = files[i] + for (j in 0 until i) { + if (frees[j] >= size) { + total += i.toLong() * triRange(offsets[2 * j + 1], size) + frees[j] -= size + offsets[2 * j + 1] += size + continue@outer + } + } + total += i.toLong() * triRange(offsets[2 * i], size) + } + return total + } + + companion object { + private fun triRange(offset: Int, size: Int) = (2 * offset + size - 1) * size / 2 + } +} 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 7d8228e..2e08526 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 @@ -9,6 +9,7 @@ val days: List = listOf( Day(6, ::Day6, Day6::part1, Day6::part2), Day(7, ::Day7, Day7::part1, Day7::part2), Day(8, ::Day8, Day8::part1, Day8::part2), + Day(9, ::Day9, Day9::part1, Day9::part2), ) data class Day( diff --git a/kt/aoc2024-lib/src/commonTest/kotlin/com/github/ephemient/aoc2024/Day9Test.kt b/kt/aoc2024-lib/src/commonTest/kotlin/com/github/ephemient/aoc2024/Day9Test.kt new file mode 100644 index 0000000..b3e281f --- /dev/null +++ b/kt/aoc2024-lib/src/commonTest/kotlin/com/github/ephemient/aoc2024/Day9Test.kt @@ -0,0 +1,23 @@ +package com.github.ephemient.aoc2024 + +import kotlin.test.Test +import kotlin.test.assertEquals + +class Day9Test { + @Test + fun part1() { + assertEquals(1928L, Day9(example).part1()) + } + + @Test + fun part2() { + assertEquals(2858L, Day9(example).part2()) + } + + companion object { + private val example = + """ + |2333133121414131402 + |""".trimMargin() + } +} \ No newline at end of file