117 lines
3.5 KiB
Kotlin
Executable File
117 lines
3.5 KiB
Kotlin
Executable File
#!/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<Int>()
|
|
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<Int>): MutableList<Int> {
|
|
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<Int>): 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<Int>): MutableList<Int> {
|
|
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<Int>, 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<Int>, 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
|
|
}
|