Files
aoc24/day09/d09p1.swift
2024-12-14 00:23:28 -08:00

68 lines
2.0 KiB
Swift

import Foundation
func readInput(_ filePath: String) throws -> Disk {
let content = try String(contentsOfFile: filePath, encoding: .ascii)
.trimmingCharacters(in: .whitespacesAndNewlines)
.map { Int(String([$0]))! }
var pos = 0
var data: [(Int, Int)] = []
var free: [(Int, Int)] = []
for (i, x) in content.enumerated() {
if i.isMultiple(of: 2) {
data.append((pos, x))
} else if x > 0 {
free.append((pos, x))
}
pos += x
}
return Disk(data: data, free: free)
}
func sumRange(start: Int, len: Int) -> Int {
return len * (start + start + len - 1) / 2
}
struct Disk {
var data: [(Int, Int)]
var free: [(Int, Int)]
var csum: Int = 0
var firstFree: Int = 0 // emulate a Deque, avoid O(n) removal from front
var compact = false
mutating func evolve() {
var (iFree, freeBlock) = free[firstFree]
var (iData, dataBlock) = data.last!
let fileNo = data.count - 1
while (dataBlock >= freeBlock) {
if iFree > iData {
if dataBlock == 0 {
data.removeLast()
}
data.enumerated().forEach { fileNo, d in
let (i, len) = d
csum += fileNo * sumRange(start: i, len: len)
}
compact = true
return
}
csum += fileNo * sumRange(start: iFree, len: freeBlock)
dataBlock -= freeBlock
data[fileNo] = (iData, dataBlock)
firstFree += 1
(iFree, freeBlock) = free[firstFree]
}
if dataBlock > 0 { // not needed; only for sanity
csum += fileNo * sumRange(start: iFree, len: dataBlock)
free[firstFree] = (iFree + dataBlock, freeBlock - dataBlock)
}
data.removeLast()
}
}
var disk = try readInput(CommandLine.arguments[1])
while !disk.compact {
disk.evolve()
//print(disk)
}
print(disk.csum)