68 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
			
		
		
	
	
			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)
 |