|
@@ -0,0 +1,37 @@
|
|
1
|
+import operator
|
|
2
|
+import re
|
|
3
|
+from collections import defaultdict
|
|
4
|
+
|
|
5
|
+POS, VEL, ACC = 0, 1, 2
|
|
6
|
+
|
|
7
|
+with open('data/20.txt') as file:
|
|
8
|
+ pattern = re.compile(r'<(.*?),(.*?),(.*?)>')
|
|
9
|
+ particles = list([list(map(int, part)) for part in pattern.findall(line)] for line in file.readlines())
|
|
10
|
+
|
|
11
|
+ # Part one: I'm not sure this will work for all inputs. This is just a rough approximation
|
|
12
|
+ # based on the fastest acceleration and then velocity. It's possible that some input will
|
|
13
|
+ # have multiple particles with the same acceleration and velocity, or that a higher
|
|
14
|
+ # velocity will be better as it works against the acceleration. It should probably be
|
|
15
|
+ # simulated fully, instead.
|
|
16
|
+
|
|
17
|
+ # Acceleration will always win out in the long run
|
|
18
|
+ min_acc = min(sum(map(abs, p[ACC])) for p in particles)
|
|
19
|
+ slowest = [(i, p) for i, p in enumerate(particles) if sum(map(abs, p[ACC])) == min_acc]
|
|
20
|
+ # Tie-break using velocity...
|
|
21
|
+ print(f'Part one: {min(slowest, key=lambda indexed: sum(map(abs, indexed[1][VEL])))[0]}')
|
|
22
|
+
|
|
23
|
+ last_collision = 0
|
|
24
|
+ while last_collision < 1000: # Assume if we don't collide in 1k iterations, we'll never collide
|
|
25
|
+ last_collision += 1
|
|
26
|
+ positions = defaultdict(list)
|
|
27
|
+ for i, particle in enumerate(particles):
|
|
28
|
+ particle[VEL] = list(map(operator.add, particle[VEL], particle[ACC]))
|
|
29
|
+ particle[POS] = list(map(operator.add, particle[POS], particle[VEL]))
|
|
30
|
+ pos_key = ','.join(map(str, particle[POS]))
|
|
31
|
+ positions[pos_key].append(particle)
|
|
32
|
+ for overlaps in positions.values():
|
|
33
|
+ if len(overlaps) > 1:
|
|
34
|
+ particles = [p for p in particles if p not in overlaps]
|
|
35
|
+ last_collision = 0
|
|
36
|
+
|
|
37
|
+ print(f'Part two: {len(particles)}')
|