/
main.swift
102 lines (92 loc) · 3 KB
/
main.swift
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
import AocUtils
enum Direction: CaseIterable {
case east, northeast, northwest, west, southwest, southeast
}
struct AxialPos: Hashable {
var p: Int = 0
var q: Int = 0
func move(_ dir: Direction) -> AxialPos {
switch dir {
case .east: return AxialPos(p: p - 1, q: q)
case .northeast: return AxialPos(p: p, q: q - 1)
case .northwest: return AxialPos(p: p + 1, q: q - 1)
case .west: return AxialPos(p: p + 1, q: q)
case .southwest: return AxialPos(p: p, q: q + 1)
case .southeast: return AxialPos(p: p - 1, q: q + 1)
}
}
func follow(_ directions: [Direction]) -> AxialPos {
return directions.reduce(self, { $0.move($1) })
}
func adjacent() -> [AxialPos] {
return Direction.allCases.map(move)
}
}
func countAdjacent(to: AxialPos, floor: Set<AxialPos>) -> Int {
return to.adjacent().reduce(0, { $0 + (floor.contains($1) ? 1 : 0) })
}
func directionsMake(desc: String) -> [Direction] {
var north: Bool?
var directions = Array<Direction>()
for ch in desc {
switch ch {
case "n":
north = true
case "s":
north = false
case "e":
if let n = north {
directions.append(n ? .northeast : .southeast)
north = nil
} else {
directions.append(.east)
}
case "w":
if let n = north {
directions.append(n ? .northwest : .southwest)
north = nil
} else {
directions.append(.west)
}
default:
assertionFailure("\(ch) is an invalid direction character")
}
}
return directions
}
let tiles = inputGet().map{ directionsMake(desc: $0) }
var flippedTiles = Dictionary<AxialPos, Bool>()
bench {
for directions in tiles {
let pos = AxialPos().follow(directions)
flippedTiles[pos] = !(flippedTiles[pos] ?? false)
}
let numBlackTiles = flippedTiles.values.reduce(0, { $0 + ($1 ? 1 : 0) })
print("🌟 Part 1 :", numBlackTiles)
}
bench {
var blackTiles = Set<AxialPos>()
for (pos, isBlack) in flippedTiles {
if isBlack {
blackTiles.insert(pos)
}
}
for _ in 1...100 {
var nextBlackTiles = Set<AxialPos>()
for blackTile in blackTiles {
let numAdjBlack = countAdjacent(to: blackTile, floor: blackTiles)
if numAdjBlack != 0 && numAdjBlack <= 2 {
// Does NOT match first rule, still black
nextBlackTiles.insert(blackTile)
}
for adjWhiteTile in blackTile.adjacent().filter({ !blackTiles.contains($0) }) {
if countAdjacent(to: adjWhiteTile, floor: blackTiles) == 2 {
// Match second rule
nextBlackTiles.insert(adjWhiteTile)
}
}
}
blackTiles = nextBlackTiles
}
print("🌟 Part 2 :", blackTiles.count)
}