import Foundation let input = loadData(day: 4) let scanner = Scanner(string: input) scanner.charactersToBeSkipped = nil extension Scanner { func field() -> (String, String)? { guard let name = scanUpToString(":"), scanString(":") != nil, let value = scanUpToCharacters(from: .whitespacesAndNewlines) else { return nil } return (name, value) } func passport() -> [String: String]? { var fields = [(String, String)]() while !isAtEnd && scanString("\n\n") == nil { _ = scanner.scanCharacters(from: .whitespacesAndNewlines) guard let field = field() else { return nil } fields.append(field) } return try? Dictionary(fields, uniquingKeysWith: { _, _ in throw NSError(domain: "error", code: 1, userInfo: nil) }) } } var valids = 0 var valid2 = 0 let requiredFields = [ "byr", "iyr", "eyr", "hgt", "hcl", "ecl", "pid", ] func validHeight(_ height: String) -> Bool { let scanner = Scanner(string: height) guard let number = scanner.scanInt() else { return false } if scanner.scanString("cm") != nil, 150...193 ~= number { return true } if scanner.scanString("in") != nil, 59...76 ~= number { return true } return false } func validHairColor(_ hcl: String) -> Bool { let scanner = Scanner(string: hcl) guard scanner.scanString("#") != nil else { return false } guard scanner.scanCharacters(from: CharacterSet(charactersIn: "0123456789abcdef"))?.count == 6 else { return falseĀ } return scanner.isAtEnd } let validEyeColors: Set = [ "amb", "blu", "brn", "gry", "grn", "hzl", "oth" ] func isValidPassportId(_ pid: String) -> Bool { return pid.count == 9 && Int(pid) != nil } while !scanner.isAtEnd { guard let passport = scanner.passport() else { fatalError() } print(passport) let valid = requiredFields.allSatisfy { passport.keys.contains($0) } if valid { valids += 1 } guard let year = passport["byr"].flatMap(Int.init), 1920...2002 ~= year else { continue } guard let issueYear = passport["iyr"].flatMap(Int.init), 2010...2020 ~= issueYear else { continue } guard let expireYear = passport["eyr"].flatMap(Int.init), 2020...2030 ~= expireYear else { continue } guard let height = passport["hgt"], validHeight(height) else { continue } guard let hairColor = passport["hcl"], validHairColor(hairColor) else { continue } guard let eyeColor = passport["ecl"], validEyeColors.contains(eyeColor) else { continue } guard let pid = passport["pid"], isValidPassportId(pid) else { continue } valid2 += 1 } print("valids", valids) print("valid2", valid2)