From 7b35583b63541cd835f3a98d872a3bf63aba38d7 Mon Sep 17 00:00:00 2001 From: Sven Weidauer Date: Thu, 24 Dec 2020 11:47:12 +0100 Subject: [PATCH] Day 24 Part 1 + 2 --- AdventOfCode2020.xcodeproj/project.pbxproj | 93 +++++++++++++++ day24/main.swift | 129 +++++++++++++++++++++ 2 files changed, 222 insertions(+) create mode 100644 day24/main.swift diff --git a/AdventOfCode2020.xcodeproj/project.pbxproj b/AdventOfCode2020.xcodeproj/project.pbxproj index 6ff0f05..9f6220f 100644 --- a/AdventOfCode2020.xcodeproj/project.pbxproj +++ b/AdventOfCode2020.xcodeproj/project.pbxproj @@ -38,6 +38,9 @@ 26DD9D2E259312410082D4F2 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DD9D2D259312410082D4F2 /* main.swift */; }; 26DD9D49259312460082D4F2 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2ACE5257ED09000702405 /* Extensions.swift */; }; 26DD9D4A259312460082D4F2 /* LoadData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2AD3A2581713A00702405 /* LoadData.swift */; }; + 26DD9DDC25949F600082D4F2 /* main.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26DD9DDB25949F600082D4F2 /* main.swift */; }; + 26DD9DF825949F690082D4F2 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2ACE5257ED09000702405 /* Extensions.swift */; }; + 26DD9DF925949F690082D4F2 /* LoadData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 26E2AD3A2581713A00702405 /* LoadData.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 */; }; @@ -214,6 +217,15 @@ ); runOnlyForDeploymentPostprocessing = 1; }; + 26DD9DD725949F600082D4F2 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; 26E2ACD3257ECFFA00702405 /* CopyFiles */ = { isa = PBXCopyFilesBuildPhase; buildActionMask = 2147483647; @@ -319,6 +331,8 @@ 26DD9CF42591C4000082D4F2 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; 26DD9D2B259312410082D4F2 /* day23 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = day23; sourceTree = BUILT_PRODUCTS_DIR; }; 26DD9D2D259312410082D4F2 /* main.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = main.swift; sourceTree = ""; }; + 26DD9DD925949F600082D4F2 /* day24 */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = day24; sourceTree = BUILT_PRODUCTS_DIR; }; + 26DD9DDB25949F600082D4F2 /* 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 = ""; }; @@ -445,6 +459,13 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 26DD9DD625949F600082D4F2 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; 26E2ACD2257ECFFA00702405 /* Frameworks */ = { isa = PBXFrameworksBuildPhase; buildActionMask = 2147483647; @@ -547,6 +568,7 @@ 26DD9CA72590759B0082D4F2 /* day21 */, 26DD9CF32591C4000082D4F2 /* day22 */, 26DD9D2C259312410082D4F2 /* day23 */, + 26DD9DDA25949F600082D4F2 /* day24 */, 268D953A25781DD80030EC4D /* Products */, ); sourceTree = ""; @@ -577,6 +599,7 @@ 26DD9CA62590759B0082D4F2 /* day21 */, 26DD9CF22591C4000082D4F2 /* day22 */, 26DD9D2B259312410082D4F2 /* day23 */, + 26DD9DD925949F600082D4F2 /* day24 */, ); name = Products; sourceTree = ""; @@ -685,6 +708,14 @@ path = day23; sourceTree = ""; }; + 26DD9DDA25949F600082D4F2 /* day24 */ = { + isa = PBXGroup; + children = ( + 26DD9DDB25949F600082D4F2 /* main.swift */, + ); + path = day24; + sourceTree = ""; + }; 26E2ACD6257ECFFA00702405 /* day8 */ = { isa = PBXGroup; children = ( @@ -1016,6 +1047,23 @@ productReference = 26DD9D2B259312410082D4F2 /* day23 */; productType = "com.apple.product-type.tool"; }; + 26DD9DD825949F600082D4F2 /* day24 */ = { + isa = PBXNativeTarget; + buildConfigurationList = 26DD9DDF25949F600082D4F2 /* Build configuration list for PBXNativeTarget "day24" */; + buildPhases = ( + 26DD9DD525949F600082D4F2 /* Sources */, + 26DD9DD625949F600082D4F2 /* Frameworks */, + 26DD9DD725949F600082D4F2 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = day24; + productName = day24; + productReference = 26DD9DD925949F600082D4F2 /* day24 */; + productType = "com.apple.product-type.tool"; + }; 26E2ACD4257ECFFA00702405 /* day8 */ = { isa = PBXNativeTarget; buildConfigurationList = 26E2ACDB257ECFFA00702405 /* Build configuration list for PBXNativeTarget "day8" */; @@ -1206,6 +1254,9 @@ 26DD9D2A259312410082D4F2 = { CreatedOnToolsVersion = 12.3; }; + 26DD9DD825949F600082D4F2 = { + CreatedOnToolsVersion = 12.3; + }; 26E2ACD4257ECFFA00702405 = { CreatedOnToolsVersion = 12.2; }; @@ -1268,6 +1319,7 @@ 26DD9CA52590759B0082D4F2 /* day21 */, 26DD9CF12591C4000082D4F2 /* day22 */, 26DD9D2A259312410082D4F2 /* day23 */, + 26DD9DD825949F600082D4F2 /* day24 */, ); }; /* End PBXProject section */ @@ -1423,6 +1475,16 @@ ); runOnlyForDeploymentPostprocessing = 0; }; + 26DD9DD525949F600082D4F2 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 26DD9DDC25949F600082D4F2 /* main.swift in Sources */, + 26DD9DF825949F690082D4F2 /* Extensions.swift in Sources */, + 26DD9DF925949F690082D4F2 /* LoadData.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; 26E2ACD1257ECFFA00702405 /* Sources */ = { isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; @@ -1969,6 +2031,28 @@ }; name = Release; }; + 26DD9DDD25949F600082D4F2 /* 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; + }; + 26DD9DDE25949F600082D4F2 /* 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 = { @@ -2308,6 +2392,15 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; + 26DD9DDF25949F600082D4F2 /* Build configuration list for PBXNativeTarget "day24" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 26DD9DDD25949F600082D4F2 /* Debug */, + 26DD9DDE25949F600082D4F2 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; 26E2ACDB257ECFFA00702405 /* Build configuration list for PBXNativeTarget "day8" */ = { isa = XCConfigurationList; buildConfigurations = ( diff --git a/day24/main.swift b/day24/main.swift new file mode 100644 index 0000000..f97a755 --- /dev/null +++ b/day24/main.swift @@ -0,0 +1,129 @@ +import Foundation + +let input = loadData(day: 24) +let scanner = Scanner(string: input) +scanner.charactersToBeSkipped = nil + +enum Direction: String, CaseIterable { + case east = "e" + case southEast = "se" + case southWest = "sw" + case west = "w" + case northWest = "nw" + case northEast = "ne" +} + +extension Scanner { + func readDirection() -> Direction? { + for dir in Direction.allCases { + if string(dir.rawValue) { + return dir + } + } + return nil + } +} + +struct Coord: Hashable { + var south: Int + var east: Int + + static let zero = Coord(south: 0, east: 0) + + mutating func move(_ direction: Direction) { + switch direction { + case .east: + east += 1 + case .southEast: + south += 1 + + case .southWest: + south += 1 + east -= 1 + + case .west: + east -= 1 + + case .northWest: + south -= 1 + + case .northEast: + south -= 1 + east += 1 + } + } + + func neighbor(_ direction: Direction) -> Coord { + var result = self + result.move(direction) + return result + } + + var neighbors: [Coord] { + Direction.allCases.map(neighbor) + } +} + +func readCoordinate() -> Coord { + var current = Coord.zero + while let direction = scanner.readDirection() { + current.move(direction) + } + precondition(scanner.string("\n")) + return current +} + +var floor: [Coord: Bool] = [:] +var northWestCorner = Coord.zero +var southEastCorner = Coord.zero + + +func expandRange(toInclude coord: Coord) { + northWestCorner.east = min(northWestCorner.east, coord.east) + northWestCorner.south = min(northWestCorner.south, coord.south) + + southEastCorner.east = max(southEastCorner.east, coord.east) + southEastCorner.south = max(southEastCorner.south, coord.south) +} + +while !scanner.isAtEnd { + let coord = readCoordinate() + expandRange(toInclude: coord) + + floor[coord, default: false].toggle() +} + +print("part 1:", floor.values.lazy.filter { $0 }.count) + +func step() -> [Coord: Bool] { + var result = floor + + for east in (northWestCorner.east - 1)...(southEastCorner.east + 1) { + for south in (northWestCorner.south - 1)...(southEastCorner.south + 1) { + let coord = Coord(south: south, east: east) + + let isBlack = floor[coord, default: false] + + let blackNeighbors = coord.neighbors + .lazy + .map { floor[$0, default: false] } + .filter { $0 } + .count + + if isBlack && (blackNeighbors == 0 || blackNeighbors > 2) { + result[coord] = false + } else if !isBlack && blackNeighbors == 2 { + result[coord] = true + expandRange(toInclude: coord) + } + } + } + + return result +} + +for _ in 0..<100 { + floor = step() +} + +print("part 2:", floor.values.lazy.filter { $0 }.count)