import random import collections INT_MASK = 0xFFFFFFFF # we use this to emulate 32-bit overflow semantics by masking off higher bits after operations class IsaacRandom(random.Random): """ Random number generator using the ISAAC algorithm. """ def seed(self, seed=None): """ Initialize internal state. The seed, if given, can be a string, an integer, or an iterable that contains integers only. If no seed is given, a fixed default state is set up; unlike our superclass, this class will not attempt to randomize the seed from outside sources. """ def mix(): init_state[0] ^= ((init_state[1]<<11)&INT_MASK); init_state[3] += init_state[0]; init_state[3] &= INT_MASK; init_state[1] += init_state[2]; init_state[1] &= INT_MASK init_state[1] ^= (init_state[2]>>2) ; init_state[4] += init_state[1]; init_state[4] &= INT_MASK; init_state[2] += init_state[3]; init_state[2] &= INT_MASK init_state[2] ^= ((init_state[3]<<8 )&INT_MASK); init_state[5] += init_state[2]; init_state[5] &= INT_MASK; init_state[3] += init_state[4]; init_state[3] &= INT_MASK init_state[3] ^= (init_state[4]>>16) ; init_state[6] += init_state[3]; init_state[6] &= INT_MASK; init_state[4] += init_state[5]; init_state[4] &= INT_MASK init_state[4] ^= ((init_state[5]<<10)&INT_MASK); init_state[7] += init_state[4]; init_state[7] &= INT_MASK; init_state[5] += init_state[6]; init_state[5] &= INT_MASK init_state[5] ^= (init_state[6]>>4 ) ; init_state[0] += init_state[5]; init_state[0] &= INT_MASK; init_state[6] += init_state[7]; init_state[6] &= INT_MASK init_state[6] ^= ((init_state[7]<<8 )&INT_MASK); init_state[1] += init_state[6]; init_state[1] &= INT_MASK; init_state[7] += init_state[0]; init_state[7] &= INT_MASK init_state[7] ^= (init_state[0]>>9 ) ; init_state[2] += init_state[7]; init_state[2] &= INT_MASK; init_state[0] += init_state[1]; init_state[0] &= INT_MASK super().seed(0) # give a chance for the superclass to reset its state - the actual seed given to it doesn't matter if seed is not None: if isinstance(seed, str): seed = [ord(x) for x in seed] elif isinstance(seed, collections.Iterable): seed = [x & INT_MASK for x in seed] elif isinstance(seed, int): val = abs(seed) seed = [] while val: seed.append(val & INT_MASK) val >>= 32 else: raise TypeError('Seed must be string, integer or iterable of integer') # make sure the seed list is exactly 256 elements long if len(seed)>256: del seed[256:] elif len(seed)<256: seed.extend([0]*(256-len(seed))) self.aa = self.bb = self.cc = 0 self.mm = [] init_state = [0x9e3779b9]*8 for _ in range(4): mix() for i in range(0, 256, 8): if seed is not None: for j in range(8): init_state[j] += seed[i+j] init_state[j] &= INT_MASK mix() self.mm += init_state if seed is not None: for i in range(0, 256, 8): for j in range(8): init_state[j] += self.mm[i+j] init_state[j] &= INT_MASK mix() for j in range(8): self.mm[i+j] = init_state[j] self.rand_count = 256 self.rand_result = [0]*256 def getstate(self): return super().getstate(), self.aa, self.bb, self.cc, self.mm, self.rand_count, self.rand_result def setstate(self, state): super().setstate(state[0]) _, self.aa, self.bb, self.cc, self.mm, self.rand_count, self.rand_result = state def _generate(self): # Generate 256 random 32-bit values and save them in an internal field. # The actual random functions will dish out these values to callers. self.cc = (self.cc + 1) & INT_MASK self.bb = (self.bb + self.cc) & INT_MASK for i in range(256): x = self.mm[i] mod = i & 3 if mod==0: self.aa ^= ((self.aa << 13) & INT_MASK) elif mod==1: self.aa ^= (self.aa >> 6) elif mod==2: self.aa ^= ((self.aa << 2) & INT_MASK) else: # mod == 3 self.aa ^= (self.aa >> 16) self.aa = (self.mm[i^128] + self.aa) & INT_MASK y = self.mm[i] = (self.mm[(x>>2) & 0xFF] + self.aa + self.bb) & INT_MASK self.rand_result[i] = self.bb = (self.mm[(y>>10) & 0xFF] + x) & INT_MASK self.rand_count = 0 def next_int(self): """Return a random integer between 0 (inclusive) and 2**32 (exclusive).""" if self.rand_count == 256: self._generate() result = self.rand_result[self.rand_count] self.rand_count += 1 return result def getrandbits(self, k): """Return a random integer between 0 (inclusive) and 2**k (exclusive).""" result = 0 ints_needed = (k+31)//32 ints_used = 0 while ints_used < ints_needed: if self.rand_count == 256: self._generate() ints_to_take = min(256-self.rand_count, ints_needed) for val in self.rand_result[self.rand_count : self.rand_count+ints_to_take]: result = (result << 32) | val self.rand_count += ints_to_take ints_used += ints_to_take result &= ((1<