| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647 |
- #!/usr/bin/env python3
- from itertools import chain, combinations, islice
- from math import gcd
- def cmp(a, b):
- return (a > b) - (a < b)
- def abssum(i):
- return sum(map(abs, i))
- def lcm(a, b):
- return abs(a * b) // gcd(a, b)
- def sim(axis):
- pos = list(axis)
- vel = [0] * len(pos)
- index_pairs = tuple(combinations(range(len(pos)), 2))
- while True:
- for i, j in index_pairs:
- diff = cmp(pos[j], pos[i])
- vel[i] += diff
- vel[j] -= diff
- for i, v in enumerate(vel):
- pos[i] += v
- yield pos, vel
- def energy_after(moons, steps):
- x, y, z = zip(*moons)
- axes = next(islice(zip(sim(x), sim(y), sim(z)), steps - 1, steps))
- pos, vel = (tuple(zip(*i)) for i in zip(*axes))
- return sum(abssum(p) * abssum(v) for p, v in zip(pos, vel))
- def axis_cycle(axis):
- seen = {}
- for step, (pos, vel) in enumerate(sim(axis)):
- ident = tuple(chain(pos, vel))
- if ident in seen:
- return step - seen[ident]
- seen[ident] = step
- def find_cycle(moons):
- x, y, z = zip(*moons)
- return lcm(lcm(axis_cycle(x), axis_cycle(y)), axis_cycle(z))
- moons = [(3, 15, 8), (5, -1, -2), (-10, 8, 2), (8, 4, -5)]
- print(energy_after(moons, 1000))
- print(find_cycle(moons))
|