aoc2021/Sources/16/16.swift

193 lines
5.3 KiB
Swift
Raw Normal View History

2021-12-16 06:52:35 +00:00
//
// File.swift
//
//
2021-12-16 07:32:02 +00:00
// Created by Max Nuding on 15.12.21.
2021-12-16 06:52:35 +00:00
//
import Foundation
import Runner
import Collections
2021-12-16 07:07:37 +00:00
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
2021-12-16 06:52:35 +00:00
}
protocol Packet {
var version: Int { get }
2021-12-16 07:32:02 +00:00
func getTotalVersion() -> Int
func getValue() -> Int
2021-12-16 06:52:35 +00:00
}
struct ValuePacket: Packet {
let version: Int
let value: Int
2021-12-16 07:32:02 +00:00
func getTotalVersion() -> Int { version }
func getValue() -> Int { value }
2021-12-16 06:52:35 +00:00
}
struct OperatorPacket: Packet {
2021-12-16 07:07:37 +00:00
let type: OperatorType
2021-12-16 06:52:35 +00:00
let version: Int
let subPackets: [Packet]
2021-12-16 07:32:02 +00:00
func getTotalVersion() -> Int { version + subPackets.map { $0.getTotalVersion() }.reduce(0, +) }
func getValue() -> Int {
let spValues = subPackets.map { $0.getValue() }
switch type {
2021-12-16 07:07:37 +00:00
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:
2021-12-16 07:32:02 +00:00
fatalError()
2021-12-16 07:07:37 +00:00
}
}
2021-12-16 07:32:02 +00:00
}
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)
2021-12-16 17:55:25 +00:00
let bytes = parts.bits().joined()
2021-12-16 07:32:02 +00:00
let packets = parsePacket(bytes: bytes)
let p: Packet = packets.0
print(p.getTotalVersion())
print(p.getValue())
}
2021-12-16 07:07:37 +00:00
2021-12-16 17:55:25 +00:00
func parsePacket<S>(bytes: S) -> (Packet, S.SubSequence) where S:StringProtocol {
let version = bytes[bytes.startIndex..<bytes.index(bytes.startIndex, offsetBy: 3)].binaryToDecimal()
let typeId = bytes[bytes.index(bytes.startIndex, offsetBy: 3)..<bytes.index(bytes.startIndex, offsetBy: 6)].binaryToDecimal()
2021-12-16 06:52:35 +00:00
var value: Packet
2021-12-16 17:55:25 +00:00
var reminder: S.SubSequence
2021-12-16 06:52:35 +00:00
switch typeId {
2021-12-16 07:07:37 +00:00
case 4:
2021-12-16 06:52:35 +00:00
let (v, r) = parseLiteralPacketValue(bytes: bytes)
value = ValuePacket(version: version, value: v)
reminder = r
default:
let (v, r) = parseOperatorPacker(bytes: bytes)
2021-12-16 07:07:37 +00:00
value = OperatorPacket(type: OperatorType(rawValue: typeId)!, version: version, subPackets: v)
2021-12-16 06:52:35 +00:00
reminder = r
}
return (value, reminder)
}
2021-12-16 17:55:25 +00:00
func parseOperatorPacker<S>(bytes: S) -> ([Packet], S.SubSequence) where S:StringProtocol {
2021-12-16 06:52:35 +00:00
let startNextBitsIndex = bytes.index(bytes.startIndex, offsetBy: 7)
let lengthTypeId = bytes[bytes.index(bytes.startIndex, offsetBy: 6)..<startNextBitsIndex].description
let isTotalLength = lengthTypeId == "0"
let nextBitsLength = isTotalLength ? 15 : 11
let endNextBitsIndex = bytes.index(startNextBitsIndex, offsetBy: nextBitsLength)
2021-12-16 17:55:25 +00:00
let nextBits = bytes[startNextBitsIndex..<endNextBitsIndex]
2021-12-16 06:52:35 +00:00
var number = nextBits.binaryToDecimal()
2021-12-16 17:55:25 +00:00
var reminder = bytes[endNextBitsIndex...]
2021-12-16 06:52:35 +00:00
var subPackets = [Packet]()
while number > 0 {
let (p, rem) = parsePacket(bytes: reminder)
number -= isTotalLength ? (reminder.count - rem.count) : 1
subPackets.append(p)
reminder = rem
}
return (subPackets, reminder)
}
2021-12-16 17:55:25 +00:00
func parseLiteralPacketValue<S>(bytes: S) -> (Int, S.SubSequence) where S:StringProtocol {
2021-12-16 06:52:35 +00:00
var index = bytes.index(bytes.startIndex, offsetBy: 6)
var ei = index
2021-12-16 17:55:25 +00:00
var bits: Substring = ""
var reminder: S.SubSequence = ""
2021-12-16 06:52:35 +00:00
while true {
let si = bytes.index(index, offsetBy: 1)
ei = bytes.index(si, offsetBy: 4)
2021-12-16 17:55:25 +00:00
bits += bytes[si..<ei]
2021-12-16 06:52:35 +00:00
if bytes[index] == "0" {
2021-12-16 17:55:25 +00:00
reminder = bytes[ei...]
2021-12-16 06:52:35 +00:00
break
}
index = bytes.index(ei, offsetBy: 0)
}
return (bits.binaryToDecimal(), reminder)
}
}
2021-12-16 17:55:25 +00:00
extension StringProtocol {
func bits() -> [String] {
2021-12-16 07:32:02 +00:00
self.map { $0.bits }
2021-12-16 06:52:35 +00:00
}
2021-12-16 17:55:25 +00:00
func binaryToDecimal() -> Int { Int(self, radix: 2)! }
2021-12-16 06:52:35 +00:00
}
extension Character {
2021-12-16 07:32:02 +00:00
var bits: String {
2021-12-16 17:55:25 +00:00
switch self.hexDigitValue! {
case 0:
2021-12-16 06:52:35 +00:00
return "0000"
2021-12-16 17:55:25 +00:00
case 1:
2021-12-16 06:52:35 +00:00
return "0001"
2021-12-16 17:55:25 +00:00
case 2:
2021-12-16 06:52:35 +00:00
return "0010"
2021-12-16 17:55:25 +00:00
case 3:
2021-12-16 06:52:35 +00:00
return "0011"
2021-12-16 17:55:25 +00:00
case 4:
2021-12-16 06:52:35 +00:00
return "0100"
2021-12-16 17:55:25 +00:00
case 5:
2021-12-16 06:52:35 +00:00
return "0101"
2021-12-16 17:55:25 +00:00
case 6:
2021-12-16 06:52:35 +00:00
return "0110"
2021-12-16 17:55:25 +00:00
case 7:
2021-12-16 06:52:35 +00:00
return "0111"
2021-12-16 17:55:25 +00:00
case 8:
2021-12-16 06:52:35 +00:00
return "1000"
2021-12-16 17:55:25 +00:00
case 9:
2021-12-16 06:52:35 +00:00
return "1001"
2021-12-16 17:55:25 +00:00
case 10:
2021-12-16 06:52:35 +00:00
return "1010"
2021-12-16 17:55:25 +00:00
case 11:
2021-12-16 06:52:35 +00:00
return "1011"
2021-12-16 17:55:25 +00:00
case 12:
2021-12-16 06:52:35 +00:00
return "1100"
2021-12-16 17:55:25 +00:00
case 13:
2021-12-16 06:52:35 +00:00
return "1101"
2021-12-16 17:55:25 +00:00
case 14:
2021-12-16 06:52:35 +00:00
return "1110"
2021-12-16 17:55:25 +00:00
case 15:
2021-12-16 06:52:35 +00:00
return "1111"
default:
2021-12-16 07:32:02 +00:00
fatalError()
}
2021-12-16 06:52:35 +00:00
}
}