#!/usr/bin/env kotlin import java.lang.RuntimeException import java.util.Scanner val scanner = Scanner(System.`in`) if (!scanner.hasNext()) { throw RuntimeException("No input given.") } val fileSystem = mutableListOf() val fileSystemDesc = scanner.nextLine().split("").filter { it.isNotEmpty() }.map { it.toInt() }.toMutableList() for (i in 0..fileSystemDesc.lastIndex) { for (j in 0 until fileSystemDesc[i]) { if ((i and 1) == 0) { fileSystem.add(i / 2) } else { fileSystem.add(-1) } } } val compressed = compressPartOne(fileSystem) val checksumOne = calculateChecksum(compressed) println("Part one checksum: $checksumOne") val compressedTwo = compressPartTwo(fileSystem) val checksumTwo = calculateChecksum(compressedTwo) println("Part two checksum: $checksumTwo") fun compressPartOne(fileSystem: MutableList): MutableList { val compressed = fileSystem.toMutableList() var freeSpacePointer = 0 var lastSectorPointer = compressed.lastIndex while (freeSpacePointer <= lastSectorPointer) { if (compressed[freeSpacePointer] != -1) { freeSpacePointer++ continue } if (compressed[lastSectorPointer] == -1) { lastSectorPointer-- continue } val tmp = compressed[freeSpacePointer] compressed[freeSpacePointer] = compressed[lastSectorPointer] compressed[lastSectorPointer] = tmp lastSectorPointer-- freeSpacePointer++ } return compressed } fun calculateChecksum(compressed: MutableList): Long { var checksum = 0L for (i in 0..compressed.lastIndex) { if (compressed[i] != -1) { checksum += i.toLong() * compressed[i].toLong() } } return checksum } fun compressPartTwo(fileSystem: MutableList): MutableList { val compressed = fileSystem.toMutableList() var relevantFileId = compressed[compressed.lastIndex] for (i in compressed.lastIndex downTo 0) { if (compressed[i] == relevantFileId && relevantFileId >= 0) { val fileSize = findFileSize(compressed, i, relevantFileId) val startIndex = findStartIndexOfEmptySpaceOfLength(compressed, fileSize) if (startIndex != -1 && startIndex < i) { for (j in 0 until fileSize) { compressed[startIndex + j] = compressed[i - j] compressed[i - j] = -1 } } relevantFileId-- } } return compressed } fun findFileSize(compressed: MutableList, i: Int, relevantFileId: Int): Int { var fileSize = 0 var j = i while (j >= 0 && compressed[j] == relevantFileId) { fileSize++ j-- } return fileSize } fun findStartIndexOfEmptySpaceOfLength(compressed: MutableList, fileSize: Int): Int { var startIndex = 0 while (startIndex < compressed.size) { if (compressed[startIndex] != -1) { startIndex++ } else { var emptySpaceLength = 0 for (i in startIndex until (startIndex + fileSize)) { if (i >= compressed.size) { return -1 } if (compressed[i] != -1) { break } else { emptySpaceLength++ } if (emptySpaceLength == fileSize) { return startIndex } } startIndex += emptySpaceLength } } return -1 }