Got part 2 in the end! The intuition that each axis is independent came to me while I was away from the keyboard!
def simulate_until_repeat(moons: List[Moon]) -> int:
Simulate `moons` until a repeated state is seen. Returns the
number of simulation steps to get to that state
def gcd(x: int, y: int) -> int:
return y if x == 0 else gcd(y % x, x)
def loop_size_for_axis(moons: List[Moon], axis) -> int:
def state(m: List[Moon]) -> str:
return str(list(axis(x) for x in m))
states = set(state(moons))
for n, m in enumerate(simulate_seq(moons)):
s = state(m)
if s in states:
def axis_x(m): return (m.pos.x, m.velocity.x)
def axis_y(m): return (m.pos.y, m.velocity.y)
def axis_z(m): return (m.pos.z, m.velocity.z)
overall_loop = 1
for a in [axis_x, axis_y, axis_z]:
loop = loop_size_for_axis(moons, a)
overall_loop = overall_loop * loop // gcd(loop, overall_loop)
We're a place where coders share, stay up-to-date and grow their careers.
We strive for transparency and don't collect excess data.