// // File.swift // // // Created by Max Nuding on 15s.12.21. // import Foundation import Runner import Collections enum OperatorType: Int { case sum = 0 case product = 1 case minimum = 2 case maximum = 3 case value = 4 case greaterThan = 5 case lessThan = 6 case equal = 7 } protocol Packet { var version: Int { get } var type: OperatorType { get } } struct ValuePacket: Packet { let type: OperatorType = .value let version: Int let value: Int } struct OperatorPacket: Packet { let type: OperatorType let version: Int let subPackets: [Packet] } class Day16: Runnable { let inputPath: String required init(inputPath: String) { self.inputPath = inputPath } public func run() { let input = try! String(contentsOfFile: inputPath) let parts = input .trimmingCharacters(in: .newlines) let bytes = parts.ToBinary().joined() let packets = parsePacket(bytes: bytes) let p: Packet = packets.0 let totalVersion = getPacketVersion(p: p) print(totalVersion) print(getPacketValue(p: p)) } func getPacketVersion(p: Packet) -> Int { //print("Found packet: \(p)") if let packet = p as? OperatorPacket { return packet.version + packet.subPackets.map(getPacketVersion).reduce(0, +) } else { return p.version } } func getPacketValue(p: Packet) -> Int { var spValues = [Int]() if let packet = p as? OperatorPacket { spValues = packet.subPackets.map(getPacketValue) } else if let packet = p as? ValuePacket { spValues = [packet.value] } else { fatalError() } switch p.type { case .sum: return spValues.reduce(0, +) case .product: return spValues.reduce(1, *) case .minimum: return spValues.min()! case .maximum: return spValues.max()! case .greaterThan: return spValues.first! > spValues.last! ? 1 : 0 case .lessThan: return spValues.first! < spValues.last! ? 1 : 0 case .equal: return spValues.first! == spValues.last! ? 1 : 0 case .value: return spValues.first! } } func parsePacket(bytes: String) -> (Packet, String) { let version = bytes[bytes.startIndex.. ([Packet], String) { let startNextBitsIndex = bytes.index(bytes.startIndex, offsetBy: 7) let lengthTypeId = bytes[bytes.index(bytes.startIndex, offsetBy: 6).. 0 { let (p, rem) = parsePacket(bytes: reminder) number -= isTotalLength ? (reminder.count - rem.count) : 1 subPackets.append(p) reminder = rem } return (subPackets, reminder) } func parseLiteralPacketValue(bytes: String) -> (Int, String) { var index = bytes.index(bytes.startIndex, offsetBy: 6) var ei = index var bits = "" var reminder = "" while true { let si = bytes.index(index, offsetBy: 1) ei = bytes.index(si, offsetBy: 4) bits += bytes[si.. [String] { self.map {$0.toBinary()!} } func binaryToDecimal() -> Int { self.reversed().enumerated().reduce(0, { p, cur in p + (cur.element == "0" ? 0 : Int(pow(2.0, Double(cur.offset)))) }) } } extension Character { func toBinary() -> String? { switch self { case "0": return "0000" case "1": return "0001" case "2": return "0010" case "3": return "0011" case "4": return "0100" case "5": return "0101" case "6": return "0110" case "7": return "0111" case "8": return "1000" case "9": return "1001" case "A": return "1010" case "B": return "1011" case "C": return "1100" case "D": return "1101" case "E": return "1110" case "F": return "1111" default: return nil} } }