-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathDay20.swift
93 lines (73 loc) · 2.37 KB
/
Day20.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
import Foundation
import Tools
/// Tried to solve part 2 with quadratic equations but got quite messy as we usually only work with ints. Instead just simulate particles and stop after a certain amount of cycles without collisions.
/// Appears that happens rather soon.
final class Day20Solver: DaySolver {
let dayNumber: Int = 20
struct Input {
let particles: [Particle]
}
struct Particle {
var position: Point3D
var velocity: Point3D
var acceleration: Point3D
}
func solvePart1(withInput input: Input) -> Int {
// we should not need to simulate anything, instead whatever has the lowest total acceleration should be closest on the long term
let particles = input.particles
var nearestParticleIndex = 0
var lowestAcceleration = particles[0].acceleration.manhattanDistance(from: .zero)
for (index, particle) in particles.enumerated() {
let acceleration = particle.acceleration.manhattanDistance(from: .zero)
if acceleration < lowestAcceleration {
lowestAcceleration = acceleration
nearestParticleIndex = index
}
}
return nearestParticleIndex
}
func solvePart2(withInput input: Input) -> Int {
var particles = input.particles
var particleIndicesToRemove: Set<Int> = []
var noChangeCounter = 0
while true {
particleIndicesToRemove.removeAll()
for i in 0 ..< particles.count {
for j in i + 1 ..< particles.count {
if particles[i].position == particles[j].position {
particleIndicesToRemove.insert(i)
particleIndicesToRemove.insert(j)
}
}
}
particles = particles.enumerated().filter {
particleIndicesToRemove.contains($0.offset) == false
}.map(\.element)
for i in 0 ..< particles.count {
particles[i].velocity += particles[i].acceleration
particles[i].position += particles[i].velocity
}
if particleIndicesToRemove.isNotEmpty {
noChangeCounter = 0
} else {
noChangeCounter += 1
}
if noChangeCounter == 20 {
return particles.count
}
}
}
func parseInput(rawString: String) -> Input {
func parsePoint3D(_ data: String) -> Point3D {
Point3D(commaSeparatedString: data[3 ..< data.count - 1])
}
return .init(particles: rawString.allLines().map { line in
let parts = line.components(separatedBy: ", ")
return Particle(
position: parsePoint3D(parts[0]),
velocity: parsePoint3D(parts[1]),
acceleration: parsePoint3D(parts[2])
)
})
}
}