AoC/2022/day11.swift

137 lines
3.6 KiB
Swift
Raw Permalink Normal View History

2022-12-11 11:20:08 +01:00
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)