AoC/2020/day16/main.swift

117 lines
3.1 KiB
Swift
Raw Permalink Normal View History

2020-12-16 07:51:50 +01:00
import Foundation
let input = loadData(day: 16)
let scanner = Scanner(string: input)
extension Scanner {
func scanRange() -> ClosedRange<Int>? {
guard let low = scanInt(),
string("-"),
let high = scanInt()
else { return nil }
return low...high
}
func scanFieldDefinition() -> (String, ClosedRange<Int>, ClosedRange<Int>)? {
var location = scanLocation
guard let name = scanUpToString(":"),
string(":"),
let first = scanRange(),
string("or"),
let second = scanRange()
else {
scanLocation = location
return nil
}
return (name, first, second)
}
func scanFieldDefinitions() -> [(String, ClosedRange<Int>, ClosedRange<Int>)] {
var result = [(String, ClosedRange<Int>, ClosedRange<Int>)]()
while let field = scanFieldDefinition() {
result.append(field)
}
return result
}
func scanTicket() -> [Int]? {
var result = [Int]()
repeat {
guard let field = scanInt() else { return nil }
result.append(field)
} while string(",")
return result
}
func scanYourTicket() -> [Int]? {
guard string("your ticket:"),
let ticket = scanTicket()
else { return nil }
return ticket
}
func scanNearbyTickets() -> [[Int]]? {
guard string("nearby tickets:") else { return nil }
var result = [[Int]]()
while !isAtEnd {
guard let ticket = scanTicket() else { return nil }
result.append(ticket)
}
return result
}
}
let definitions = scanner.scanFieldDefinitions()
guard let yourTicket = scanner.scanYourTicket(),
let nearbyTickets = scanner.scanNearbyTickets()
else { fatalError() }
func isValid(_ value: Int) -> Bool {
definitions.contains {
$0.1.contains(value) || $0.2.contains(value)
}
}
func isValid(_ ticket: [Int]) -> Bool {
ticket.allSatisfy(isValid)
}
let invalidSums = nearbyTickets
.flatten()
.filter( { !isValid($0) } )
.reduce(0, +)
print(invalidSums)
var possibleFields: [Set<String>] = Array(repeating: Set(definitions.map { $0.0 }), count: yourTicket.count)
for ticket in nearbyTickets where isValid(ticket) {
for (index, value) in ticket.enumerated() {
for (name, first, second) in definitions {
if !(first.contains(value) || second.contains(value)) {
possibleFields[index].remove(name)
}
}
}
}
for index in possibleFields.indices.sorted(by: { possibleFields[$0].count < possibleFields[$1].count }) {
guard possibleFields[index].count == 1, let key = possibleFields[index].first else { fatalError() }
for i in possibleFields.indices where i != index {
possibleFields[i].remove(key)
}
}
let mapping = possibleFields.map { $0.first! }
let result = mapping.enumerated()
.map { ($0.element, yourTicket[$0.offset]) }
.filter { $0.0.hasPrefix("departure") }
.map { $0.1 }
.reduce(1, *)
print(result)