From 00d14b6e19c90ab4501d7d6a474733a4ce1a3783 Mon Sep 17 00:00:00 2001 From: Sven Weidauer Date: Mon, 21 Dec 2020 21:41:49 +0100 Subject: [PATCH] Day 21 --- AdventOfCode2020.xcodeproj/project.pbxproj | 93 ++++++++++++++++++++++ day21/main.swift | 91 +++++++++++++++++++++ 2 files changed, 184 insertions(+) create mode 100644 day21/main.swift diff --git a/AdventOfCode2020.xcodeproj/project.pbxproj b/AdventOfCode2020.xcodeproj/project.pbxproj index 2546822..250548a 100644 --- a/AdventOfCode2020.xcodeproj/project.pbxproj +++ b/AdventOfCode2020.xcodeproj/project.pbxproj @@ -29,6 +29,9 @@ 26DD9C74258F2CEE0082D4F2 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DD9C73258F2CEE0082D4F2 /* main.swift */; }; 26DD9C8C258F2CF80082D4F2 /* LoadData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2AD3A2581713A00702405 /* LoadData.swift */; }; 26DD9C8D258F2CF80082D4F2 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2ACE5257ED09000702405 /* Extensions.swift */; }; + 26DD9CA92590759B0082D4F2 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DD9CA82590759B0082D4F2 /* main.swift */; }; + 26DD9CC2259075A50082D4F2 /* LoadData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2AD3A2581713A00702405 /* LoadData.swift */; }; + 26DD9CD82590767F0082D4F2 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2ACE5257ED09000702405 /* Extensions.swift */; }; 26E2ACD8257ECFFA00702405 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2ACD7257ECFFA00702405 /* main.swift */; }; 26E2ACE6257ED09000702405 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2ACE5257ED09000702405 /* Extensions.swift */; }; 26E2ACE7257ED09000702405 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2ACE5257ED09000702405 /* Extensions.swift */; }; @@ -178,6 +181,15 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 26DD9CA42590759B0082D4F2 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; 26E2ACD3257ECFFA00702405 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -277,6 +289,8 @@ 26DD9C40258DEAC70082D4F2 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 26DD9C71258F2CEE0082D4F2 /* day20 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = day20; sourceTree = BUILT_PRODUCTS_DIR; }; 26DD9C73258F2CEE0082D4F2 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + 26DD9CA62590759B0082D4F2 /* day21 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = day21; sourceTree = BUILT_PRODUCTS_DIR; }; + 26DD9CA82590759B0082D4F2 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 26E2ACD5257ECFFA00702405 /* day8 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = day8; sourceTree = BUILT_PRODUCTS_DIR; }; 26E2ACD7257ECFFA00702405 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 26E2ACE5257ED09000702405 /* Extensions.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = ""; }; @@ -382,6 +396,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 26DD9CA32590759B0082D4F2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 26E2ACD2257ECFFA00702405 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -481,6 +502,7 @@ 26BD88A3258C818300E92A8E /* day18 */, 26DD9C3F258DEAC70082D4F2 /* day19 */, 26DD9C72258F2CEE0082D4F2 /* day20 */, + 26DD9CA72590759B0082D4F2 /* day21 */, 268D953A25781DD80030EC4D /* Products */, ); sourceTree = ""; @@ -508,6 +530,7 @@ 26BD88A2258C818300E92A8E /* day18 */, 26DD9C3E258DEAC70082D4F2 /* day19 */, 26DD9C71258F2CEE0082D4F2 /* day20 */, + 26DD9CA62590759B0082D4F2 /* day21 */, ); name = Products; sourceTree = ""; @@ -592,6 +615,14 @@ path = day20; sourceTree = ""; }; + 26DD9CA72590759B0082D4F2 /* day21 */ = { + isa = PBXGroup; + children = ( + 26DD9CA82590759B0082D4F2 /* main.swift */, + ); + path = day21; + sourceTree = ""; + }; 26E2ACD6257ECFFA00702405 /* day8 */ = { isa = PBXGroup; children = ( @@ -872,6 +903,23 @@ productReference = 26DD9C71258F2CEE0082D4F2 /* day20 */; productType = "com.apple.product-type.tool"; }; + 26DD9CA52590759B0082D4F2 /* day21 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 26DD9CAC2590759B0082D4F2 /* Build configuration list for PBXNativeTarget "day21" */; + buildPhases = ( + 26DD9CA22590759B0082D4F2 /* Sources */, + 26DD9CA32590759B0082D4F2 /* Frameworks */, + 26DD9CA42590759B0082D4F2 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = day21; + productName = day21; + productReference = 26DD9CA62590759B0082D4F2 /* day21 */; + productType = "com.apple.product-type.tool"; + }; 26E2ACD4257ECFFA00702405 /* day8 */ = { isa = PBXNativeTarget; buildConfigurationList = 26E2ACDB257ECFFA00702405 /* Build configuration list for PBXNativeTarget "day8" */; @@ -1053,6 +1101,9 @@ 26DD9C70258F2CEE0082D4F2 = { CreatedOnToolsVersion = 12.3; }; + 26DD9CA52590759B0082D4F2 = { + CreatedOnToolsVersion = 12.3; + }; 26E2ACD4257ECFFA00702405 = { CreatedOnToolsVersion = 12.2; }; @@ -1112,6 +1163,7 @@ 26BD88A1258C818300E92A8E /* day18 */, 26DD9C3D258DEAC70082D4F2 /* day19 */, 26DD9C70258F2CEE0082D4F2 /* day20 */, + 26DD9CA52590759B0082D4F2 /* day21 */, ); }; /* End PBXProject section */ @@ -1237,6 +1289,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 26DD9CA22590759B0082D4F2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 26DD9CA92590759B0082D4F2 /* main.swift in Sources */, + 26DD9CD82590767F0082D4F2 /* Extensions.swift in Sources */, + 26DD9CC2259075A50082D4F2 /* LoadData.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 26E2ACD1257ECFFA00702405 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1717,6 +1779,28 @@ }; name = Release; }; + 26DD9CAA2590759B0082D4F2 /* 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; + }; + 26DD9CAB2590759B0082D4F2 /* 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; + }; 26E2ACD9257ECFFA00702405 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { @@ -2029,6 +2113,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 26DD9CAC2590759B0082D4F2 /* Build configuration list for PBXNativeTarget "day21" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 26DD9CAA2590759B0082D4F2 /* Debug */, + 26DD9CAB2590759B0082D4F2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 26E2ACDB257ECFFA00702405 /* Build configuration list for PBXNativeTarget "day8" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/day21/main.swift b/day21/main.swift new file mode 100644 index 0000000..dd24bf3 --- /dev/null +++ b/day21/main.swift @@ -0,0 +1,91 @@ +import Foundation +let input = loadData(day: 21) + +let scanner = Scanner(string: input) +scanner.charactersToBeSkipped = .whitespaces + +extension Scanner { + func ingredient() -> String? { + scanUpToCharacters(from: .whitespaces) + } + + func allergens() -> Set? { + guard string("(contains") else { return nil } + var result: Set = [] + let end = CharacterSet(charactersIn: ",)") + repeat { + guard let allergen = scanUpToCharacters(from: end) else { return nil } + result.insert(allergen) + } while string(",") + guard string(")") else { return nil } + return result + } + + func end() -> Set? { + let allergens = self.allergens() + guard string("\n") else { return nil } + return allergens ?? [] + } + + typealias Food = (ingredients: Set, allergens: Set) + + func food() -> Food? { + var ingredients = Set() + while true { + guard let ingredient = self.ingredient() else { return nil } + ingredients.insert(ingredient) + + if let end = self.end() { + return (ingredients, end) + } + } + } + + func foods() -> [Food] { + var result: [Food] = [] + while !isAtEnd, let food = self.food() { + result.append(food) + } + return result + } +} + +let data = scanner.foods() + +var possibleIngredientsByAllergen: [String: Set] = [:] +var allIngredients: Set = [] +var allergens: [(String, String)] = [] + +for (ingredients, allergens) in data { + allIngredients.formUnion(ingredients) + for allergen in allergens { + if let possible = possibleIngredientsByAllergen[allergen] { + possibleIngredientsByAllergen[allergen] = possible.intersection(ingredients) + } else { + possibleIngredientsByAllergen[allergen] = ingredients + } + } +} + +while !possibleIngredientsByAllergen.isEmpty { + for (allergen, possible) in possibleIngredientsByAllergen where possible.count == 1 { + let ingredient = possible.first! + allIngredients.remove(ingredient) + possibleIngredientsByAllergen.removeValue(forKey: allergen) + allergens.append((allergen, ingredient)) + for key in possibleIngredientsByAllergen.keys { + possibleIngredientsByAllergen[key]?.remove(ingredient) + } + } +} + +let count = data.reduce(0) { $0 + $1.ingredients.intersection(allIngredients).count } + +print("part 1:", count) + +let canonicalDangerousList = allergens + .sorted { $0.0 < $1.0 } + .map { $0.1 } + .joined(separator: ",") + +print("part 2:", canonicalDangerousList)