-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay16.swift
86 lines (67 loc) · 2.22 KB
/
Day16.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
import Foundation
import Tools
/// In part 2 we detect the number of rounds the pattern repeats and after that we only have to perform the instructions the remainder amount of times.
final class Day16Solver: DaySolver {
let dayNumber: Int = 16
struct Input {
let instructions: [Instruction]
}
enum Instruction {
case spin(size: Int)
case swapByIndex(a: Int, b: Int)
case swapByProgram(a: String, b: String)
}
private func generateStartLine() -> [String] {
(0 ..< 16).map { String(asciiString: AsciiString([AsciiCharacter.a + $0])) }
}
private func shuffleLine(_ line: [String], instructions: [Instruction]) -> [String] {
var line = line
for instruction in instructions {
switch instruction {
case .spin(let size):
line = Array(line[line.count - size ..< line.count] + line[0 ..< (line.count - size)])
case .swapByIndex(let a, let b):
line.swapAt(a, b)
case .swapByProgram(let a, let b):
line.swapAt(line.firstIndex(of: a)!, line.firstIndex(of: b)!)
}
}
return line
}
func solvePart1(withInput input: Input) -> String {
var line: [String] = generateStartLine()
line = shuffleLine(line, instructions: input.instructions)
return line.joined()
}
func solvePart2(withInput input: Input) -> String {
let startLine: [String] = generateStartLine()
var line = startLine
// find repeating pattern
var loopSize = 0
while true {
line = shuffleLine(line, instructions: input.instructions)
loopSize += 1
if line == startLine {
break
}
}
let remainderSteps = 1_000_000_000 % loopSize
for _ in 0 ..< remainderSteps {
line = shuffleLine(line, instructions: input.instructions)
}
return line.joined()
}
func parseInput(rawString: String) -> Input {
return .init(instructions: rawString.allLines().first!.components(separatedBy: ",").map { part in
if let values = part.getCapturedValues(pattern: #"s([0-9]*)"#) {
.spin(size: Int(values[0])!)
} else if let values = part.getCapturedValues(pattern: #"x([0-9]*)\/([0-9]*)"#) {
.swapByIndex(a: Int(values[0])!, b: Int(values[1])!)
} else if let values = part.getCapturedValues(pattern: #"p([a-z]*)\/([a-z]*)"#) {
.swapByProgram(a: values[0], b: values[1])
} else {
fatalError()
}
})
}
}