From 69bd0027d408d9accd771f4fcfb249f008d4c3d7 Mon Sep 17 00:00:00 2001 From: "Mohsen.Biglari" Date: Mon, 9 Dec 2024 16:17:41 +0100 Subject: [PATCH] Day 9 --- src/Day09.kt | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 114 insertions(+) create mode 100644 src/Day09.kt diff --git a/src/Day09.kt b/src/Day09.kt new file mode 100644 index 0000000..4c2d5ab --- /dev/null +++ b/src/Day09.kt @@ -0,0 +1,114 @@ +import java.util.* + +fun main() { + + data class Gap( + val index: Int, + val count: Int, + ) { + val end = index + count - 1 + + fun fillFirstCell() = fillNCell(1) + fun fillNCell(n: Int) = Gap(index = index + n, count = count - n) + } + + data class File( + val id: Int, + val index: Int, + val count: Int, + ) { + val end = index + count - 1 + + fun emptyLastCell() = File(id = id, index = index, count = count - 1) + } + + fun String.toDisk(): Triple, LinkedList, LinkedList> { + val length = fold(0) { acc, c -> acc + c.digitToInt() } + val arr = Array(size = length) { 0 } + val gaps = LinkedList() + val files = LinkedList() + var isFile = true + var index = 0 + var label = 0 + forEach { c -> + val num = if (isFile) label++ else -1 + isFile = !isFile + val count = c.digitToInt() + if (num == -1 && count > 0) gaps.add(Gap(index = index, count = count)) + if (num >= 0) files.add(File(id = num, index = index, count = count)) + repeat(count) { + arr[index++] = num + } + } + return Triple(arr, files, gaps) + } + + class DiskManager( + private val disk: Array, + private val files: LinkedList, + private val gaps: LinkedList, + ) { + + fun fillGapsFromEnd() { + while (gaps.isNotEmpty()) { + val firstGap = gaps.first() + val lastFile = files.last + if (firstGap.index >= lastFile.index) return + + disk[firstGap.index] = lastFile.id + disk[lastFile.end] = -1 + gaps.removeFirst() + firstGap.fillFirstCell().also { + if (it.count > 0) gaps.addFirst(it) + } + files.removeLast() + lastFile.emptyLastCell().also { + if (it.count > 0) files.addLast(it) + } + } + } + + fun fillGapsWithWholeFilesFromEnd() { + for (file in files.reversed()) { + val firstPossibleGapIndex = gaps.indexOfFirst { it.count >= file.count && it.end < file.index } + val firstPossibleGap = gaps.getOrNull(firstPossibleGapIndex) ?: continue + repeat(file.count) { + disk[firstPossibleGap.index + it] = file.id + disk[file.index + it] = -1 + } + gaps.removeAt(firstPossibleGapIndex) + firstPossibleGap.fillNCell(file.count).also { + if (it.count > 0) gaps.add(firstPossibleGapIndex, it) + } + } + } + + fun checksumOfOrderedDisk(): Long { + return disk.foldIndexed(0L) { index, acc, id -> + acc + if (id == -1) 0 else id * index + } + } + } + + fun part1(input: List): Long { + val (disk, files, gaps) = input[0].toDisk() + return DiskManager(disk = disk, files = files, gaps = gaps) + .apply { fillGapsFromEnd() } + .checksumOfOrderedDisk() + } + + fun part2(input: List): Long { + val (disk, files, gaps) = input[0].toDisk() + return DiskManager(disk = disk, files = files, gaps = gaps) + .apply { fillGapsWithWholeFilesFromEnd() } + .checksumOfOrderedDisk() + } + + val testInput1 = readInput("Day09_test") + check(part1(testInput1) == 1928L) + check(part2(testInput1) == 2858L) + + val input = readInput("Day09") + part1(input).println() + part2(input).println() +}