-
Notifications
You must be signed in to change notification settings - Fork 0
/
lottery_sim1.py
155 lines (126 loc) · 5.68 KB
/
lottery_sim1.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
#With executor.map
import numpy as np
import multiprocessing
import time
from tqdm import tqdm
import plotly.graph_objects as go
from concurrent.futures import ProcessPoolExecutor
import random
# Lottery simulation variables
chosenNumbers = np.array([22, 3, 7, 8, 30])
plays = 10000000
num_processes = multiprocessing.cpu_count()
#_______________________________________________________________________________________________________
# Lottery number generation class
class LotteryGen:
@staticmethod
def generate_numbers(start, end, count):
"""Generate a sorted list of unique random numbers within a specified range."""
numbers = random.sample(range(start, end + 1), count)
numbers.sort()
return numbers
@staticmethod
def generate_multiple_sets(times, start, end, count):
"""Generate multiple sets of sorted unique random numbers within a specified range."""
return [LotteryGen.generate_numbers(start, end, count) for _ in range(times)]
#_______________________________________________________________________________________________________
# Super5 Simulation class
class Super5Simulation:
def __init__(self, chosen_numbers, plays, num_processes):
self.chosen_numbers = chosen_numbers
self.plays = plays
self.num_processes = num_processes
def play_lottery(self, chunk_size):
"""Simulate a single chunk of lottery plays."""
local_match_counts = np.zeros(6, dtype=int)
np.random.seed() # Ensures a different seed in each process
for _ in range(chunk_size):
rolled_numbers = np.random.randint(1, 45, size=5)
matches = np.sum(np.isin(rolled_numbers, self.chosen_numbers))
local_match_counts[matches] += 1
return local_match_counts
def print_results(self, match_counts):
"""Print the results of the simulation."""
total_plays = sum(match_counts)
odds = [total_plays / count if count > 0 else float('inf') for count in match_counts]
print(f"Super5: {self.chosen_numbers.tolist()}")
print(f"0 Matches: {match_counts[0]:,} (1 in {odds[0]:,.0f})")
print(f"1 Match: {match_counts[1]:,} (1 in {odds[1]:,.0f})")
print(f"2 Matches: {match_counts[2]:,} (1 in {odds[2]:,.0f})")
print(f"3 Matches: {match_counts[3]:,} (1 in {odds[3]:,.0f})")
print(f"4 Matches: {match_counts[4]:,} (1 in {odds[4]:,.0f})")
print(f"5 Matches: {match_counts[5]:,} (1 in {odds[5]:,.0f})")
def plot_results(self, match_counts):
"""Plot the results of the simulation."""
categories = ['0 Matches', '1 Match', '2 Matches', '3 Matches', '4 Matches', '5 Matches']
values = match_counts.tolist()
fig = go.Figure()
fig.add_trace(go.Bar(x=categories, y=values, name='Matches'))
fig.update_layout(
title='Lottery Matches Count',
xaxis_title='Matches',
yaxis_title='Counts',
hovermode='x unified', # Combine hover info for all bars at a given x
barmode='group', # Grouped bar chart
legend=dict(x=0, y=1.0, bgcolor='rgba(255, 255, 255, 0.5)', bordercolor='rgba(255, 255, 255, 0.5)'),
annotations=[
dict(text='Matches Count', x=0.5, y=1.05, showarrow=False, xref='paper', yref='paper')
]
)
fig.show()
def run_simulation(self):
"""Run the Super5 lottery simulation."""
start_time = time.time()
chunk_size = 10000
total_chunks = self.plays // chunk_size
match_counts = np.zeros(6, dtype=int)
with tqdm(total=self.plays, desc="Playing Super5...") as pbar:
with ProcessPoolExecutor(max_workers=self.num_processes) as executor:
results = executor.map(self.play_lottery, [chunk_size] * total_chunks)
for result in results:
match_counts += result
pbar.update(chunk_size)
self.print_results(match_counts)
end_time = time.time()
elapsed_time = end_time - start_time
print(f"Total execution time: {elapsed_time:.2f} seconds")
self.plot_results(match_counts)
#_______________________________________________________________________________________________________
# Menu class to handle user interactions
class Menu:
@staticmethod
def display():
"""Display the menu options."""
print('\n\nSelect an option:\n')
print('1. Super5')
print('2. Powerball')
print('3. Mega Millions')
print('4. Run Super5 Lottery Simulation')
print('Q. Quit')
@staticmethod
def process_choice(choice):
"""Process the user's menu choice."""
if choice == '1':
print('\nSuper5:', LotteryGen.generate_numbers(1, 45, 5))
elif choice == '2':
print('\nPowerball:', LotteryGen.generate_numbers(1, 55, 5), LotteryGen.generate_numbers(1, 42, 1))
elif choice == '3':
print('\nMega Millions:', LotteryGen.generate_numbers(1, 75, 5), LotteryGen.generate_numbers(1, 15, 1))
elif choice == '4':
sim = Super5Simulation(chosenNumbers, plays, num_processes)
sim.run_simulation()
else:
print("Invalid choice. Please try again.")
# Main worker function
def main_function():
while True:
Menu.display()
choice = input('\nEnter your choice: ').lower()
if choice.startswith('q'):
print("Done! Thanks for playing.")
break
else:
Menu.process_choice(choice)
#_______________________________________________________________________________________________________
if __name__ == '__main__':
main_function()