From c815aeb94254c5207659f818fd40c09ab96330c4 Mon Sep 17 00:00:00 2001 From: Sven Weidauer Date: Wed, 16 Dec 2020 07:51:50 +0100 Subject: [PATCH] Day 16 --- AdventOfCode2020.xcodeproj/project.pbxproj | 93 +++++++++++++++++ common/Extensions.swift | 6 ++ day16/main.swift | 116 +++++++++++++++++++++ 3 files changed, 215 insertions(+) create mode 100644 day16/main.swift diff --git a/AdventOfCode2020.xcodeproj/project.pbxproj b/AdventOfCode2020.xcodeproj/project.pbxproj index 8056ba1..57110f0 100644 --- a/AdventOfCode2020.xcodeproj/project.pbxproj +++ b/AdventOfCode2020.xcodeproj/project.pbxproj @@ -8,6 +8,9 @@ /* Begin PBXBuildFile section */ 26176242257DFD0800D00A66 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26176241257DFD0800D00A66 /* main.swift */; }; + 261C554825895FB70035FEC0 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 261C554725895FB70035FEC0 /* main.swift */; }; + 261C555C25895FBF0035FEC0 /* LoadData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2AD3A2581713A00702405 /* LoadData.swift */; }; + 261C555D25895FBF0035FEC0 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2ACE5257ED09000702405 /* Extensions.swift */; }; 268D953D25781DD80030EC4D /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 268D953C25781DD80030EC4D /* main.swift */; }; 268D954B25781F740030EC4D /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 268D954A25781F740030EC4D /* main.swift */; }; 268D955C257904250030EC4D /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 268D955B257904250030EC4D /* main.swift */; }; @@ -64,6 +67,15 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 261C554325895FB70035FEC0 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; 268D953725781DD80030EC4D /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -195,6 +207,8 @@ /* Begin PBXFileReference section */ 2617623F257DFD0800D00A66 /* day7 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = day7; sourceTree = BUILT_PRODUCTS_DIR; }; 26176241257DFD0800D00A66 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + 261C554525895FB70035FEC0 /* day16 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = day16; sourceTree = BUILT_PRODUCTS_DIR; }; + 261C554725895FB70035FEC0 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 268D953925781DD80030EC4D /* day1 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = day1; sourceTree = BUILT_PRODUCTS_DIR; }; 268D953C25781DD80030EC4D /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 268D954825781F740030EC4D /* day2 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = day2; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -235,6 +249,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 261C554225895FB70035FEC0 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 268D953625781DD80030EC4D /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -344,6 +365,14 @@ path = day7; sourceTree = ""; }; + 261C554625895FB70035FEC0 /* day16 */ = { + isa = PBXGroup; + children = ( + 261C554725895FB70035FEC0 /* main.swift */, + ); + path = day16; + sourceTree = ""; + }; 268D953025781DD80030EC4D = { isa = PBXGroup; children = ( @@ -363,6 +392,7 @@ 26E2ADAA2586024700702405 /* day13 */, 26E2ADE225873BBE00702405 /* day14 */, 26E2AE0B2587E07A00702405 /* day15 */, + 261C554625895FB70035FEC0 /* day16 */, 268D953A25781DD80030EC4D /* Products */, ); sourceTree = ""; @@ -385,6 +415,7 @@ 26E2ADA92586024700702405 /* day13 */, 26E2ADE125873BBD00702405 /* day14 */, 26E2AE0A2587E07A00702405 /* day15 */, + 261C554525895FB70035FEC0 /* day16 */, ); name = Products; sourceTree = ""; @@ -530,6 +561,23 @@ productReference = 2617623F257DFD0800D00A66 /* day7 */; productType = "com.apple.product-type.tool"; }; + 261C554425895FB70035FEC0 /* day16 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 261C554B25895FB70035FEC0 /* Build configuration list for PBXNativeTarget "day16" */; + buildPhases = ( + 261C554125895FB70035FEC0 /* Sources */, + 261C554225895FB70035FEC0 /* Frameworks */, + 261C554325895FB70035FEC0 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = day16; + productName = day16; + productReference = 261C554525895FB70035FEC0 /* day16 */; + productType = "com.apple.product-type.tool"; + }; 268D953825781DD80030EC4D /* day1 */ = { isa = PBXNativeTarget; buildConfigurationList = 268D954025781DD80030EC4D /* Build configuration list for PBXNativeTarget "day1" */; @@ -780,6 +828,9 @@ 2617623E257DFD0800D00A66 = { CreatedOnToolsVersion = 12.2; }; + 261C554425895FB70035FEC0 = { + CreatedOnToolsVersion = 12.2; + }; 268D953825781DD80030EC4D = { CreatedOnToolsVersion = 12.2; }; @@ -852,6 +903,7 @@ 26E2ADA82586024700702405 /* day13 */, 26E2ADE025873BBD00702405 /* day14 */, 26E2AE092587E07A00702405 /* day15 */, + 261C554425895FB70035FEC0 /* day16 */, ); }; /* End PBXProject section */ @@ -867,6 +919,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 261C554125895FB70035FEC0 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 261C554825895FB70035FEC0 /* main.swift in Sources */, + 261C555D25895FBF0035FEC0 /* Extensions.swift in Sources */, + 261C555C25895FBF0035FEC0 /* LoadData.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 268D953525781DD80030EC4D /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1032,6 +1094,28 @@ }; name = Release; }; + 261C554925895FB70035FEC0 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 722B335UM5; + ENABLE_HARDENED_RUNTIME = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Debug; + }; + 261C554A25895FB70035FEC0 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = 722B335UM5; + ENABLE_HARDENED_RUNTIME = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; + }; + name = Release; + }; 268D953E25781DD80030EC4D /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -1467,6 +1551,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 261C554B25895FB70035FEC0 /* Build configuration list for PBXNativeTarget "day16" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 261C554925895FB70035FEC0 /* Debug */, + 261C554A25895FB70035FEC0 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 268D953425781DD80030EC4D /* Build configuration list for PBXProject "AdventOfCode2020" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/common/Extensions.swift b/common/Extensions.swift index 76ec492..72906a4 100644 --- a/common/Extensions.swift +++ b/common/Extensions.swift @@ -31,3 +31,9 @@ extension Sequence { return self } } + +extension Collection where Element: Collection { + func flatten() -> [Element.Element] { + flatMap { $0 } + } +} diff --git a/day16/main.swift b/day16/main.swift new file mode 100644 index 0000000..93ce447 --- /dev/null +++ b/day16/main.swift @@ -0,0 +1,116 @@ +import Foundation + +let input = loadData(day: 16) +let scanner = Scanner(string: input) + +extension Scanner { + func scanRange() -> ClosedRange? { + guard let low = scanInt(), + string("-"), + let high = scanInt() + else { return nil } + return low...high + } + + func scanFieldDefinition() -> (String, ClosedRange, ClosedRange)? { + var location = scanLocation + guard let name = scanUpToString(":"), + string(":"), + let first = scanRange(), + string("or"), + let second = scanRange() + else { + scanLocation = location + return nil + } + return (name, first, second) + } + + func scanFieldDefinitions() -> [(String, ClosedRange, ClosedRange)] { + var result = [(String, ClosedRange, ClosedRange)]() + while let field = scanFieldDefinition() { + result.append(field) + } + + return result + } + + func scanTicket() -> [Int]? { + var result = [Int]() + repeat { + guard let field = scanInt() else { return nil } + result.append(field) + } while string(",") + return result + } + + func scanYourTicket() -> [Int]? { + guard string("your ticket:"), + let ticket = scanTicket() + else { return nil } + return ticket + } + + func scanNearbyTickets() -> [[Int]]? { + guard string("nearby tickets:") else { return nil } + var result = [[Int]]() + while !isAtEnd { + guard let ticket = scanTicket() else { return nil } + result.append(ticket) + } + return result + } +} + +let definitions = scanner.scanFieldDefinitions() +guard let yourTicket = scanner.scanYourTicket(), + let nearbyTickets = scanner.scanNearbyTickets() +else { fatalError() } + + +func isValid(_ value: Int) -> Bool { + definitions.contains { + $0.1.contains(value) || $0.2.contains(value) + } +} + +func isValid(_ ticket: [Int]) -> Bool { + ticket.allSatisfy(isValid) +} + +let invalidSums = nearbyTickets + .flatten() + .filter( { !isValid($0) } ) + .reduce(0, +) + +print(invalidSums) + + +var possibleFields: [Set] = Array(repeating: Set(definitions.map { $0.0 }), count: yourTicket.count) + +for ticket in nearbyTickets where isValid(ticket) { + for (index, value) in ticket.enumerated() { + for (name, first, second) in definitions { + if !(first.contains(value) || second.contains(value)) { + possibleFields[index].remove(name) + } + } + } +} + +for index in possibleFields.indices.sorted(by: { possibleFields[$0].count < possibleFields[$1].count }) { + guard possibleFields[index].count == 1, let key = possibleFields[index].first else { fatalError() } + for i in possibleFields.indices where i != index { + possibleFields[i].remove(key) + } +} + +let mapping = possibleFields.map { $0.first! } + +let result = mapping.enumerated() + .map { ($0.element, yourTicket[$0.offset]) } + .filter { $0.0.hasPrefix("departure") } + .map { $0.1 } + .reduce(1, *) + +print(result)