|
#!/usr/bin/env python |
|
import random |
|
|
|
# ------------------ |
|
# Raffle algorithm |
|
# ------------------ |
|
|
|
def raffle(number_of_winners, entries, random_source): |
|
|
|
|
|
winners = set() # hold unique values only |
|
hat = list(entries) |
|
|
|
while len(winners) < number_of_winners: |
|
hat_size = len(hat) |
|
if hat_size == 0: |
|
raise ValueError("Not enough unique entries for {} winners".format(number_of_winners)) |
|
|
|
random_index = random_source.randrange(hat_size) |
|
drawn_entry = hat.pop(random_index) # get and remove random_index |
|
winners.add(drawn_entry) |
|
|
|
return winners |
|
|
|
|
|
# ------------------------ |
|
# Command-line interface |
|
# ------------------------ |
|
|
|
USAGE="""USAGE: raffle.py number_of_winners [entries_file...] |
|
|
|
number_of_winners (required): |
|
The number of unique winners for the raffle |
|
entries_file (optional, repeated): |
|
Text file(s) with one raffle entry per line |
|
If none given, entries will be read from standard input (`-`) |
|
|
|
""" |
|
|
|
if __name__ == '__main__': |
|
import sys |
|
import os |
|
import fileinput |
|
|
|
number_of_winners = 0; |
|
montecarlo = False; |
|
monte_carlo_runs = 0; |
|
i = 1; |
|
loops = 1; |
|
|
|
try: |
|
while i < len(sys.argv): |
|
if sys.argv[i] == "-montecarlo": |
|
montecarlo = True; |
|
loops = int(sys.argv[i+1]) |
|
i += 1 |
|
elif number_of_winners == 0: |
|
number_of_winners = int(sys.argv[i]) |
|
else: |
|
entry_files = sys.argv[i] |
|
i += 1; |
|
except (IndexError, ValueError) as e: |
|
sys.stderr.write(USAGE) |
|
sys.exit(1) |
|
|
|
entries = [line.strip() for line in fileinput.input(files=entry_files)] |
|
names = {x: 0 for x in list(entries)} |
|
|
|
seed = os.environ.get('RANDOM_SEED') |
|
random_source = random.Random(seed) if seed else random.SystemRandom() |
|
|
|
#sys.stderr.write("Selecting {} winners from {}...\n".format(number_of_winners, entries)) |
|
for i in range(loops): |
|
winners = raffle(number_of_winners, entries, random_source) |
|
for i in range(number_of_winners): |
|
next_winner = winners.pop() |
|
new_value = names.get(next_winner) + 1 |
|
names.update({next_winner: new_value}) |
|
|
|
|
|
for k, v in names.items(): |
|
print(k, '{0:.2f}%'.format((float(v)*100)/float(loops))) |