136 lines
3.6 KiB
Swift
136 lines
3.6 KiB
Swift
import Foundation
|
|
|
|
typealias Item = Int
|
|
|
|
class Monkey {
|
|
var items: [Item]
|
|
var operation: Operation
|
|
var operand: Operand
|
|
var test: Int
|
|
var trueTarget: Int
|
|
var falseTarget: Int
|
|
var inspectCount = 0
|
|
|
|
init(items: [Item], operation: Operation, operand: Operand, test: Int, trueTarget: Int, falseTarget: Int) {
|
|
self.items = items
|
|
self.operation = operation
|
|
self.operand = operand
|
|
self.test = test
|
|
self.trueTarget = trueTarget
|
|
self.falseTarget = falseTarget
|
|
}
|
|
|
|
func run() {
|
|
for item in items {
|
|
inspectCount += 1
|
|
let newLevel = operation.apply(item, operand.value(item: item)) / 3
|
|
let target = newLevel.isMultiple(of: test) ? trueTarget : falseTarget
|
|
monkeys[target].add(newLevel)
|
|
}
|
|
items.removeAll()
|
|
}
|
|
|
|
func add(_ item: Item) {
|
|
items.append(item)
|
|
}
|
|
}
|
|
|
|
extension Monkey {
|
|
convenience init?(scanner: Scanner) {
|
|
guard scanner.scanString("Monkey") != nil, scanner.scanInt() != nil, scanner.scanString(":") != nil else {
|
|
return nil
|
|
}
|
|
|
|
guard scanner.scanString("Starting items:") != nil else { return nil }
|
|
let items = scanner.scanList().map(Item.init(_:))
|
|
|
|
guard scanner.scanString("Operation: new = old") != nil, let operation = scanner.scanOperation(), let operand = scanner.scanOperand() else { return nil }
|
|
|
|
guard scanner.scanString("Test: divisible by") != nil, let test = scanner.scanInt() else { return nil }
|
|
guard scanner.scanString("If true: throw to monkey") != nil, let trueTarget = scanner.scanInt() else { return nil }
|
|
guard scanner.scanString("If false: throw to monkey") != nil, let falseTarget = scanner.scanInt() else { return nil }
|
|
|
|
self.init(items: items, operation: operation, operand: operand, test: test, trueTarget: trueTarget, falseTarget: falseTarget)
|
|
}
|
|
}
|
|
|
|
|
|
enum Operation: String, CaseIterable {
|
|
case add = "+"
|
|
case multiply = "*"
|
|
|
|
func apply(_ lhs: Item, _ rhs: Item) -> Item {
|
|
switch self {
|
|
case .add: return lhs + rhs
|
|
case .multiply: return lhs * rhs
|
|
}
|
|
}
|
|
}
|
|
|
|
enum Operand {
|
|
case number(Int)
|
|
case old
|
|
|
|
func value(item: Item) -> Item {
|
|
switch self {
|
|
case .number(let number): return Item(number)
|
|
case .old: return item
|
|
}
|
|
}
|
|
}
|
|
|
|
extension Scanner {
|
|
func scanList() -> [Int] {
|
|
var result: [Int] = []
|
|
while true {
|
|
guard let int = scanInt() else {
|
|
break
|
|
}
|
|
result.append(int)
|
|
guard scanString(",") != nil else {
|
|
break
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
func scanOperation() -> Operation? {
|
|
for op in Operation.allCases {
|
|
if scanString(op.rawValue) != nil {
|
|
return op
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func scanOperand() -> Operand? {
|
|
if let int = scanInt() {
|
|
return .number(int)
|
|
}
|
|
|
|
if scanString("old") != nil {
|
|
return .old
|
|
}
|
|
|
|
return nil
|
|
}
|
|
}
|
|
|
|
let input = try String(contentsOf: URL(fileURLWithPath: "day11.input"))
|
|
let scanner = Scanner(string: input)
|
|
var monkeys: [Monkey] = []
|
|
|
|
while !scanner.isAtEnd, let monkey = Monkey(scanner: scanner) {
|
|
monkeys.append(monkey)
|
|
}
|
|
|
|
|
|
for _ in 0..<20 {
|
|
for monkey in monkeys {
|
|
monkey.run()
|
|
}
|
|
}
|
|
|
|
|
|
let monkeyBusiness = monkeys.map(\.inspectCount).sorted(by: >).prefix(2).reduce(1, *)
|
|
print("Part 1:", monkeyBusiness)
|