// // File.swift // // // Created by Max Nuding on 04.12.21. // import Foundation import Runner struct Board { var numbers: [[Int?]] var hasWon = false mutating func crossOf(num: Int) -> Bool { for (rowNumber, row) in numbers.enumerated() { if let colNumber = row.firstIndex(of: num) { numbers[rowNumber][colNumber] = nil //print("Found at: \(rowNumber),\(colNumber)") return true } } return false } mutating func checkHasWon() -> Bool { var found = false defer { hasWon = hasWon || found } found = numbers.contains { row in row.allSatisfy { $0 == nil } } if found { return true } found = numbers.indices.contains { columnIndex in numbers.allSatisfy { $0[columnIndex] == nil } } hasWon = found return hasWon } func calculateScore() -> Int { numbers .reduce([], +) .compactMap { $0 } .reduce(0, +) } } struct Day04: Runnable { let inputPath: String func run() { let input = try! String(contentsOfFile: inputPath) var lines = input .components(separatedBy: .newlines) let inputNumbers = lines .removeFirst() .split(separator: ",") .map { Int($0)! } _ = lines.removeFirst() //empty seperator line var boards = lines .split(separator: "") .map { boardLines in Board(numbers: boardLines.map { $0.split(separator: " ").map { num in Int(num)! } }) } run(boards: &boards, inputNumbers: inputNumbers) } func run(boards: inout [Board], inputNumbers: [Int]) { var countWon = 0 for inputNumber in inputNumbers { for (idx, var board) in boards.enumerated() { if board.crossOf(num: inputNumber) && !board.hasWon && board.checkHasWon() { if countWon == 0 { print(board.calculateScore() * inputNumber) } countWon += 1 } if countWon == boards.count { print(board.calculateScore() * inputNumber) return } boards[idx] = board } } } }