Python3 – Spinning rings

Codewars Assignment

Imagine two rings with numbers on them. The inner ring spins clockwise and the outer ring spins anti-clockwise. We start with both rings aligned on 0 at the top, and on each move we spin each ring by 1. How many moves will it take before both rings show the same number at the top again?

The inner ring has integers from 0 to innerMax and the outer ring has integers from 0 to outerMax, where innerMax and outerMax are integers >= 1.

e.g. if innerMax is 2 and outerMax is 3 then after
1 move: inner = 2, outer = 1
2 moves: inner = 1, outer = 2
3 moves: inner = 0, outer = 3
4 moves: inner = 2, outer = 0
5 moves: inner = 1, outer = 1
Therefore it takes 5 moves for the two rings to reach the same number
Therefore spinningRings(2, 3) = 5
e.g. if innerMax is 3 and outerMax is 2 then after
1 move: inner = 3, outer = 1
2 moves: inner = 2, outer = 2
Therefore it takes 2 moves for the two rings to reach the same number
spinningRings(3, 2) = 2

Martin’s comment

This looks so easy at first but for this solution some basics mathematics is needed. Firstly I though it would be so good to use MOD mathematics function to iterate but I was unable to get it working over zero. If you look for the best Kata solution you will see that someone got it solved the way I firstly wanted (by the way his idea was just to add 1 in mod equitation to get zero number issue solved).

Best solution

from itertools import count
def spinning_rings(inner_max, outer_max):
 return next(i for i in count(1) if i % (outer_max + 1) == -i % (inner_max + 1))

Comment:  This is of course not my solution but it is genius one. I wanted to make something similar but definitely even if I would solve the problem with iteration over zero digit I would be unable to make this extremely short lambda function.

My solution

 import numpy

 def spinning_rings(inner_max, outer_max):
   i = 0
   inner = numpy.arange(0,inner_max+1)[::-1]
   outer = numpy.arange(0,outer_max+1)
   while True:
     if numpy.roll(inner,-i)[0] == numpy.roll(outer,-i-1)[0]:
       return i+1
     i += 1

 print(spinning_rings(3, 3))


Practically not smart solution at all. Not mentioning how much work it took me to debug it to work properly and yes, I am using numpy. I am not very proud of my solution and definitely not the time it took me (almost hour) but hope in future my results will be better. At least it works…