AoC/2020/day14/main.swift

94 lines
2.3 KiB
Swift
Raw Permalink Normal View History

2020-12-14 18:49:31 +01:00
import Foundation
2020-12-14 19:02:48 +01:00
let input = loadData(day: 14)
2020-12-14 18:49:31 +01:00
2020-12-14 19:02:48 +01:00
class Problem {
let scanner: Scanner
2020-12-14 18:49:31 +01:00
2020-12-14 19:02:48 +01:00
/// Each bit where the mask is "1" is set here
var maskBits: UInt64 = 0
2020-12-14 18:49:31 +01:00
2020-12-14 19:02:48 +01:00
/// Each bit where the mask is "X" is set here
var maskUsed: UInt64 = 0
var mem: [UInt64:UInt64] = [:]
2020-12-14 18:49:31 +01:00
2020-12-14 19:02:48 +01:00
var writeMem: (Problem, UInt64, UInt64) -> Void
2020-12-14 18:49:31 +01:00
2020-12-14 19:02:48 +01:00
init(_ input: String, writeMem: @escaping (Problem, UInt64, UInt64) -> Void) {
scanner = Scanner(string: input)
self.writeMem = writeMem
}
2020-12-14 18:49:31 +01:00
2020-12-14 19:02:48 +01:00
func run() {
while !scanner.isAtEnd {
if scanner.string("mask = "), let mask = scanner.scanCharacters(from: Self.maskSet) {
readMask(mask)
} else if scanner.string("mem["), let addr = scanner.scanUInt64(), scanner.string("] = "), let value = scanner.scanUInt64() {
writeMem(self, addr, value)
} else {
assertionFailure("Invalid input")
}
}
2020-12-14 18:49:31 +01:00
2020-12-14 19:02:48 +01:00
print("sum", mem.values.reduce(0, +))
}
2020-12-14 18:49:31 +01:00
2020-12-14 19:02:48 +01:00
private func readMask(_ mask: String) {
assert(mask.count == 36)
maskBits = 0
maskUsed = 0
for char in mask {
maskBits <<= 1
maskUsed <<= 1
switch char {
case "1": maskBits |= 1
case "0": break
case "X": maskUsed |= 1
default: assertionFailure("Invalid character in mask")
}
2020-12-14 18:49:31 +01:00
}
}
2020-12-14 19:02:48 +01:00
static private let maskSet = CharacterSet(charactersIn: "01X")
2020-12-14 18:49:31 +01:00
}
2020-12-14 19:02:48 +01:00
let part1 = Problem(input) { problem, addr, value in
problem.mem[addr] = (value & problem.maskUsed) | problem.maskBits
2020-12-14 18:49:31 +01:00
}
2020-12-14 19:02:48 +01:00
part1.run()
2020-12-14 18:49:31 +01:00
func possibleValues(_ mask: UInt64) -> [UInt64] {
var values: [UInt64] = []
var mask = mask
for i in 0..<36 {
if mask & 1 != 0 {
let bit: UInt64 = 1 << i
if values.isEmpty {
values.append(0)
values.append(bit)
} else {
values.append(contentsOf: values.map { $0 | bit })
}
}
mask >>= 1
}
return values
}
2020-12-14 19:02:48 +01:00
let part2 = Problem(input) { problem, addr, value in
for i in possibleValues(problem.maskUsed) {
let effective = i | ((addr | problem.maskBits) & ~problem.maskUsed)
problem.mem[effective] = value
2020-12-14 18:49:31 +01:00
}
}
2020-12-14 19:02:48 +01:00
part2.run()