diff --git a/diceware/random_sources.py b/diceware/random_sources.py index 67264855b241cd103d5cefd96addb44f46ce130f..5c45db1fa7037435034ca1eaa34123c253224018 100644 --- a/diceware/random_sources.py +++ b/diceware/random_sources.py @@ -131,9 +131,15 @@ class RealDiceRandomSource(object): We make sure that `num_rolls`, the number of rolls, is in an acceptable range and issue an hint about the procedure. """ + use_modulo=False + if num_rolls == 0: + raise(ValueError) if num_rolls < 1: - raise ValueError( - "Must provide at least %s items" % self.dice_sides) + # If this happens, there are less values in the sequence to choose from than there are dice sides. + # We will generate a large integer (larger than 100*len(sequence)), + # and use modulo to select from it + num_rolls = int(math.ceil(math.log(100*len(sequence), self.dice_sides))) + use_modulo=True if (self.dice_sides ** num_rolls) < len(sequence): print( "Warning: entropy is reduced! Using only first %s of %s " @@ -144,13 +150,13 @@ class RealDiceRandomSource(object): print( "Please roll %s dice (or a single dice %s times)." % ( num_rolls, num_rolls)) - return + return num_rolls, use_modulo def choice(self, sequence): """Pick one item out of `sequence`. """ num_rolls = int(math.log(len(sequence), self.dice_sides)) - self.pre_check(num_rolls, sequence) + num_rolls, use_modulo = self.pre_check(num_rolls, sequence) result = 0 for i in range(num_rolls, 0, -1): rolled = None @@ -159,4 +165,6 @@ class RealDiceRandomSource(object): rolled = input_func( "What number shows dice number %s? " % (num_rolls - i + 1)) result += ((self.dice_sides ** (i - 1)) * (int(rolled) - 1)) + if use_modulo: + result = result % len(sequence) return sequence[result]