Files
aoc24/day24/d24p2.swift
2024-12-24 00:34:37 -08:00

85 lines
2.9 KiB
Swift

import Foundation
typealias Op = (Bool, Bool) -> Bool
typealias Gate = (String, Op, String, String)
struct Circuit : CustomStringConvertible {
let gates: [Gate]
var nodes: [String: Bool]
var pendingEndNodes: Set<String>
var description: String {
nodes.map { "\($0): \($1 ? 1 : 0)" }.sorted().joined(separator: "\n") +
"\n\(pendingEndNodes)"
}
func value(of prefix: String) -> Int? {
if pendingEndNodes.count > 0 { return nil }
return nodes.keys.filter { $0.starts(with: prefix) }
.sorted().reversed().reduce(0) { $0 * 2 + (nodes[$1]! ? 1 : 0) }
}
mutating func run(gate: Gate) {
let (in1, op, in2, out) = gate
if let v1 = nodes[in1], let v2 = nodes[in2] {
nodes[out] = op(v1, v2)
pendingEndNodes.remove(out)
}
}
mutating func run() {
gates.forEach { run(gate: $0) }
}
}
func readInput(_ filePath: String) throws -> Circuit {
let content = try String(contentsOfFile: filePath, encoding: .ascii)
let nodeRe = try Regex(#"([a-z0-9]+): (0|1)"#)
let gateRe = try Regex(#"([a-z0-9]+) (AND|OR|XOR) ([a-z0-9]+) -> ([a-z0-9]+)"#)
let opMap: [String: Op] = [
"AND": { $0 && $1 },
"OR": { $0 || $1 },
"XOR": { $0 != $1 }
]
var nodes: [String: Bool] = [:]
var gates: [Gate] = []
var endNodes: Set<String> = []
for line in content.split(separator: "\n") {
if let m = line.wholeMatch(of: nodeRe) {
let node = String(m.output[1].substring!)
let val = m.output[2].substring! == "1"
nodes[node] = val
}
if let m = line.wholeMatch(of: gateRe) {
let in1 = String(m.output[1].substring!)
let op = opMap[String(m.output[2].substring!)]!
let in2 = String(m.output[3].substring!)
let out = String(m.output[4].substring!)
gates.append((in1, op, in2, out))
if out.starts(with: "z") {
endNodes.insert(out)
}
}
}
return Circuit(gates: gates, nodes: nodes, pendingEndNodes: endNodes)
}
var circuit = try readInput(CommandLine.arguments[1])
// just print out the wrong bits for manual debugging. See input.dot
while true {
if let z = circuit.value(of: "z"),
let x = circuit.value(of: "x"),
let y = circuit.value(of: "y")
{
print("x: " + String(x, radix: 2).reversed())
print("y: " + String(y, radix: 2).reversed())
let zStr = String(z, radix: 2).reversed()
let pStr = String(x+y, radix: 2).reversed()
let zHighlight = zip(zStr, pStr).map { dz, dp -> String in
dz == dp ? String(dz) : "\u{001B}[41m\(dz)\u{001B}[0m"
}
print("z: " + zHighlight.joined())
print("\u{001B}[4m!: \(String(pStr))\u{001B}[0m")
print(" \((0..<zStr.count).map { String($0 % 10) }.joined())")
break
}
circuit.run()
}