Dueling Generators

Part 1


In [36]:
class FancyGen(object):
    
    def __init__(self, start, factor):
        self.start = start
        self.factor = factor
        self.q = 2147483647
        
    def __iter__(self):
        self.a = self.start
        return self

    def __next__(self):
        n = (self.a * self.factor) % self.q
        self.a = n
        return n

def compare_lowest_bits(n, m):
    n = n % (2 ** 16)
    m = m % (2 ** 16)
    return n == m

def duel(starta, startb):
    N = 40 * 10 ** 6
    count = 0
    gena = iter(FancyGen(starta, 16807))
    genb = iter(FancyGen(startb, 48271))
    for _ in range(N):
        if compare_lowest_bits(next(gena), next(genb)):
            count += 1
    return count

Test


In [37]:
%%time
duel(65, 8921)


CPU times: user 1min 1s, sys: 0 ns, total: 1min 1s
Wall time: 1min 1s
Out[37]:
588

Solution


In [38]:
%%time
duel(289, 629)


CPU times: user 1min 2s, sys: 0 ns, total: 1min 2s
Wall time: 1min 2s
Out[38]:
638

Part 2


In [42]:
def just_multiples(gen, divisor):
    for n in gen:
        if n % divisor == 0:
            yield n

In [52]:
def picky_duel(starta, startb):
    N = 5 * 10 ** 6
    count = 0
    gena = just_multiples(FancyGen(starta, 16807), 4)
    genb = just_multiples(FancyGen(startb, 48271), 8)
    for _ in range(N):
        n = next(gena)
        m = next(genb)
        if compare_lowest_bits(n, m):
            count += 1
    return count

Test


In [53]:
%%time
picky_duel(65, 8921)


CPU times: user 40 s, sys: 8 ms, total: 40 s
Wall time: 40 s
Out[53]:
309

Solution


In [54]:
%%time
picky_duel(289, 629)


CPU times: user 43.3 s, sys: 36 ms, total: 43.3 s
Wall time: 43.4 s
Out[54]:
343