75 lines
2 KiB
Swift
75 lines
2 KiB
Swift
|
import Foundation
|
||
|
|
||
|
let input = loadData(day: 7)
|
||
|
|
||
|
|
||
|
let scanner = Scanner(string: input)
|
||
|
|
||
|
struct Rule {
|
||
|
var count: Int
|
||
|
var color: String
|
||
|
}
|
||
|
|
||
|
extension Scanner {
|
||
|
func scanRule() -> Rule? {
|
||
|
guard let count = scanInt(),
|
||
|
let color = scanUpToString(count == 1 ? " bag" : " bags"),
|
||
|
scanString(count == 1 ? "bag" : "bags") != nil
|
||
|
else { return nil }
|
||
|
return Rule(count: count, color: color)
|
||
|
}
|
||
|
|
||
|
func scanRuleSet() -> (String, [Rule])? {
|
||
|
guard
|
||
|
let color = scanUpToString(" bags contain"),
|
||
|
scanString("bags contain") != nil else { return nil }
|
||
|
if scanString("no other bags.") != nil {
|
||
|
return (color, [])
|
||
|
}
|
||
|
|
||
|
var rules: [Rule] = []
|
||
|
repeat {
|
||
|
guard let rule = scanRule() else { return nil }
|
||
|
rules.append(rule)
|
||
|
} while scanString(",") != nil
|
||
|
|
||
|
guard scanString(".") != nil else { return nil }
|
||
|
|
||
|
return (color, rules)
|
||
|
}
|
||
|
|
||
|
func scanAllRules() -> [String: [Rule]]? {
|
||
|
var result: [String: [Rule]] = [:]
|
||
|
while !isAtEnd {
|
||
|
guard let (color, rules) = scanRuleSet() else { return nil }
|
||
|
result[color] = rules
|
||
|
}
|
||
|
return result
|
||
|
}
|
||
|
}
|
||
|
|
||
|
guard let rules = scanner.scanAllRules() else { fatalError() }
|
||
|
//print(rules)
|
||
|
|
||
|
func findPath(rules: [String: [Rule]], from: String, to: String) -> Bool {
|
||
|
guard let from = rules[from] else { return false }
|
||
|
if from.contains(where: { $0.color == to }) {
|
||
|
return true
|
||
|
}
|
||
|
|
||
|
return from.contains(where: { findPath(rules: rules, from: $0.color, to: to) })
|
||
|
}
|
||
|
|
||
|
let count = rules.lazy.filter { findPath(rules: rules, from: $0.key, to: "shiny gold") }.count
|
||
|
|
||
|
print("count", count)
|
||
|
|
||
|
func bagsInside(rules: [String: [Rule]], color: String) -> Int {
|
||
|
guard let from = rules[color] else { return 0 }
|
||
|
return from.reduce(0) { accum, bag in
|
||
|
accum + bag.count + bag.count * bagsInside(rules: rules, color: bag.color)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
print("total bags", bagsInside(rules: rules, color: "shiny gold"))
|