Reformat code to pythonic standards
This commit is contained in:
1 parent
9630657710
commit
31b335b7e8
4 files changed
+116
-49
No files matched your search
@@ -1,5 +1,6 @@
|
|||||||
from datetime import datetime
|
import random
|
||||||
from collections import Counter
|
from collections import Counter
|
||||||
|
from datetime import datetime
|
||||||
|
|
||||||
import numpy as np
|
import numpy as np
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
@@ -7,11 +8,12 @@ from sklearn.ensemble import RandomForestRegressor
|
|||||||
from sqlalchemy import select
|
from sqlalchemy import select
|
||||||
|
|
||||||
from data.database import Base, dal
|
from data.database import Base, dal
|
||||||
from lottery_predictor.config import RANDOM_SEED, GAME_INFO
|
from lottery_predictor.config import GAME_INFO
|
||||||
|
|
||||||
|
|
||||||
def load_dataframe_by_dates(
|
def load_dataframe_by_dates(
|
||||||
game: str, start_date: datetime | None = None, end_date: datetime | None = None
|
game: str, start_date: datetime | None = None,
|
||||||
|
end_date: datetime | None = None,
|
||||||
) -> pd.DataFrame:
|
) -> pd.DataFrame:
|
||||||
"""
|
"""
|
||||||
:param game: the name of the game to get data for
|
:param game: the name of the game to get data for
|
||||||
@@ -29,12 +31,16 @@ def load_dataframe_by_dates(
|
|||||||
target_table = Base.metadata.tables.get(game_dict['db_table_name'])
|
target_table = Base.metadata.tables.get(game_dict['db_table_name'])
|
||||||
if start_date is not None and end_date is not None:
|
if start_date is not None and end_date is not None:
|
||||||
sql_statement = (select(target_table)
|
sql_statement = (select(target_table)
|
||||||
.where(target_table.columns.draw_date >= start_date)
|
.where(
|
||||||
|
target_table.columns.draw_date >= start_date,
|
||||||
|
)
|
||||||
.where(target_table.columns.draw_date <= end_date)
|
.where(target_table.columns.draw_date <= end_date)
|
||||||
.order_by(target_table.columns.draw_date.desc()))
|
.order_by(target_table.columns.draw_date.desc()))
|
||||||
elif start_date is not None and end_date is None:
|
elif start_date is not None and end_date is None:
|
||||||
sql_statement = (select(target_table)
|
sql_statement = (select(target_table)
|
||||||
.where(target_table.columns.draw_date >= start_date)
|
.where(
|
||||||
|
target_table.columns.draw_date >= start_date,
|
||||||
|
)
|
||||||
.order_by(target_table.columns.draw_date.desc()))
|
.order_by(target_table.columns.draw_date.desc()))
|
||||||
elif start_date is None and end_date is not None:
|
elif start_date is None and end_date is not None:
|
||||||
sql_statement = (select(target_table)
|
sql_statement = (select(target_table)
|
||||||
@@ -68,12 +74,15 @@ def load_dataframe_most_recent(game: str, limit: int = 10) -> pd.DataFrame:
|
|||||||
.limit(limit))
|
.limit(limit))
|
||||||
return pd.read_sql(sql_statement, session.bind)
|
return pd.read_sql(sql_statement, session.bind)
|
||||||
else:
|
else:
|
||||||
raise ValueError('Limit must be a positive integer greater than zero.')
|
raise ValueError(
|
||||||
|
'Limit must be a positive integer greater than zero.',
|
||||||
|
)
|
||||||
else:
|
else:
|
||||||
raise ValueError('An invalid table name was provided.')
|
raise ValueError('An invalid table name was provided.')
|
||||||
|
|
||||||
|
|
||||||
def prepare_split_data(data: np.ndarray, window_size: int = 10) -> tuple[np.ndarray, np.ndarray, np.ndarray]:
|
def prepare_split_data(data: np.ndarray, window_size: int = 10) -> tuple[
|
||||||
|
np.ndarray, np.ndarray, np.ndarray]:
|
||||||
# Clean the data by removing the draw_date and multiplier columns
|
# Clean the data by removing the draw_date and multiplier columns
|
||||||
clean_data = data[:, 1:7]
|
clean_data = data[:, 1:7]
|
||||||
|
|
||||||
@@ -81,7 +90,7 @@ def prepare_split_data(data: np.ndarray, window_size: int = 10) -> tuple[np.ndar
|
|||||||
if len(clean_data) <= window_size:
|
if len(clean_data) <= window_size:
|
||||||
raise ValueError(
|
raise ValueError(
|
||||||
f"Not enough data! Dataset has {len(clean_data)} rows, "
|
f"Not enough data! Dataset has {len(clean_data)} rows, "
|
||||||
f"but window_size requires at least {window_size + 1} rows."
|
f"but window_size requires at least {window_size + 1} rows.",
|
||||||
)
|
)
|
||||||
|
|
||||||
# Calculate the indices for all windows at once
|
# Calculate the indices for all windows at once
|
||||||
@@ -99,7 +108,11 @@ def prepare_split_data(data: np.ndarray, window_size: int = 10) -> tuple[np.ndar
|
|||||||
return x, y_field, y_game
|
return x, y_field, y_game
|
||||||
|
|
||||||
|
|
||||||
def make_prediction(data_frame: pd.DataFrame, window_size: int = 10) -> tuple[np.ndarray, np.ndarray]:
|
def make_prediction(data_frame: pd.DataFrame, window_size: int = 10) -> tuple[
|
||||||
|
np.ndarray, np.ndarray]:
|
||||||
|
# Get a random number
|
||||||
|
state = random.randint(1000, 300_000)
|
||||||
|
|
||||||
# Convert the data_frame to a numpy array for slicing
|
# Convert the data_frame to a numpy array for slicing
|
||||||
data = data_frame.values
|
data = data_frame.values
|
||||||
|
|
||||||
@@ -107,25 +120,27 @@ def make_prediction(data_frame: pd.DataFrame, window_size: int = 10) -> tuple[np
|
|||||||
x, y_field, y_game = prepare_split_data(data, window_size=window_size)
|
x, y_field, y_game = prepare_split_data(data, window_size=window_size)
|
||||||
|
|
||||||
# Train the model for the field balls
|
# Train the model for the field balls
|
||||||
field_model = RandomForestRegressor(n_estimators=200, random_state=RANDOM_SEED)
|
field_model = RandomForestRegressor(n_estimators=200, random_state=state)
|
||||||
field_model.fit(x, y_field)
|
field_model.fit(x, y_field)
|
||||||
|
|
||||||
# Train the model for the game ball
|
# Train the model for the game ball
|
||||||
game_model = RandomForestRegressor(n_estimators=200, random_state=RANDOM_SEED)
|
game_model = RandomForestRegressor(n_estimators=200, random_state=state)
|
||||||
game_model.fit(x, y_game)
|
game_model.fit(x, y_game)
|
||||||
|
|
||||||
# Predict the next draw
|
# Predict the next draw
|
||||||
clean_data = data[:, 1:7]
|
clean_data = data[:, 1:7]
|
||||||
current_window = clean_data[-window_size:].flatten().reshape(1, -1)
|
current_window = clean_data[-window_size:].flatten().reshape(1, -1)
|
||||||
# Get predictions and round to the nearest whole number
|
# Get predictions and round to the nearest whole number
|
||||||
predicted_field = np.sort(np.round(field_model.predict(current_window)).astype(int))
|
predicted_field = np.sort(
|
||||||
|
np.round(field_model.predict(current_window)).astype(int),
|
||||||
|
)
|
||||||
predicted_game = np.round(game_model.predict(current_window)).astype(int)
|
predicted_game = np.round(game_model.predict(current_window)).astype(int)
|
||||||
|
|
||||||
return predicted_field[0], predicted_game[0]
|
return predicted_field[0], predicted_game[0]
|
||||||
|
|
||||||
|
|
||||||
def get_most_common_number(
|
def get_most_common_number(
|
||||||
data_frame: pd.DataFrame, columns: list | None = None, top: int = 1
|
data_frame: pd.DataFrame, columns: list | None = None, top: int = 1,
|
||||||
) -> list[int]:
|
) -> list[int]:
|
||||||
"""
|
"""
|
||||||
:param data_frame: a pandas DataFrame containing the data
|
:param data_frame: a pandas DataFrame containing the data
|
||||||
@@ -135,14 +150,16 @@ def get_most_common_number(
|
|||||||
:returns: a list of the most common numbers
|
:returns: a list of the most common numbers
|
||||||
"""
|
"""
|
||||||
if columns is None:
|
if columns is None:
|
||||||
columns = ['main_ball1', 'main_ball2', 'main_ball3', 'main_ball4', 'main_ball5']
|
columns = [
|
||||||
|
'main_ball1', 'main_ball2', 'main_ball3', 'main_ball4', 'main_ball5',
|
||||||
|
]
|
||||||
flat_numbers = data_frame[columns].values.flatten()
|
flat_numbers = data_frame[columns].values.flatten()
|
||||||
counts = Counter(flat_numbers)
|
counts = Counter(flat_numbers)
|
||||||
return [int(num) for num, _ in counts.most_common(top)]
|
return [int(num) for num, _ in counts.most_common(top)]
|
||||||
|
|
||||||
|
|
||||||
def get_least_common_number(
|
def get_least_common_number(
|
||||||
data_frame: pd.DataFrame, columns: list | None = None, bottom: int = 1
|
data_frame: pd.DataFrame, columns: list | None = None, bottom: int = 1,
|
||||||
) -> list[int]:
|
) -> list[int]:
|
||||||
"""
|
"""
|
||||||
:param data_frame: a pandas DataFrame containing the data
|
:param data_frame: a pandas DataFrame containing the data
|
||||||
@@ -152,23 +169,30 @@ def get_least_common_number(
|
|||||||
:returns: a list of the least common numbers
|
:returns: a list of the least common numbers
|
||||||
"""
|
"""
|
||||||
if columns is None:
|
if columns is None:
|
||||||
columns = ['main_ball1', 'main_ball2', 'main_ball3', 'main_ball4', 'main_ball5']
|
columns = [
|
||||||
|
'main_ball1', 'main_ball2', 'main_ball3', 'main_ball4', 'main_ball5',
|
||||||
|
]
|
||||||
flat_numbers = data_frame[columns].values.flatten()
|
flat_numbers = data_frame[columns].values.flatten()
|
||||||
counts = Counter(flat_numbers)
|
counts = Counter(flat_numbers)
|
||||||
return list(reversed([int(num) for num, _ in counts.most_common()[-bottom:]]))
|
return list(
|
||||||
|
reversed([int(num) for num, _ in counts.most_common()[-bottom:]]),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def calculate_probabilities(
|
def calculate_probabilities(
|
||||||
data_frame: pd.DataFrame, max_number: int, columns: list | None = None
|
data_frame: pd.DataFrame, max_number: int, columns: list | None = None,
|
||||||
) -> dict[int, float]:
|
) -> dict[int, float]:
|
||||||
"""
|
"""
|
||||||
:param data_frame: A pandas DataFrame containing the data to calculate probabilities for
|
:param data_frame: A pandas DataFrame containing the data to calculate
|
||||||
|
probabilities for
|
||||||
:param max_number: The maximum number possible in the data_frame
|
:param max_number: The maximum number possible in the data_frame
|
||||||
:param columns: The list of column names to use from the data_frame
|
:param columns: The list of column names to use from the data_frame
|
||||||
:returns dict: A dictionary containing the probabilities
|
:returns dict: A dictionary containing the probabilities
|
||||||
"""
|
"""
|
||||||
if columns is None:
|
if columns is None:
|
||||||
columns = ['main_ball1', 'main_ball2', 'main_ball3', 'main_ball4', 'main_ball5']
|
columns = [
|
||||||
|
'main_ball1', 'main_ball2', 'main_ball3', 'main_ball4', 'main_ball5',
|
||||||
|
]
|
||||||
if data_frame.empty:
|
if data_frame.empty:
|
||||||
return dict()
|
return dict()
|
||||||
|
|
||||||
@@ -177,9 +201,11 @@ def calculate_probabilities(
|
|||||||
# count all the occurrences of each number
|
# count all the occurrences of each number
|
||||||
counts = Counter(all_numbers)
|
counts = Counter(all_numbers)
|
||||||
# calculate the basic probability of each number occurring again
|
# calculate the basic probability of each number occurring again
|
||||||
probabilities = {num: counts.get(num, 0) / (max_number + 1) for num in range(1, max_number + 1)}
|
probabilities = {num: counts.get(num, 0) / (max_number + 1) for num in
|
||||||
|
range(1, max_number + 1)}
|
||||||
|
|
||||||
# if any calculation is greater than one, use what is to the right of the decimal point as the value
|
# if any calculation is greater than one, use what is to the right of the
|
||||||
|
# decimal point as the value
|
||||||
for key, value in probabilities.items():
|
for key, value in probabilities.items():
|
||||||
if value > 1:
|
if value > 1:
|
||||||
probabilities[key] = value - int(str(value).split('.')[0])
|
probabilities[key] = value - int(str(value).split('.')[0])
|
||||||
@@ -188,16 +214,20 @@ def calculate_probabilities(
|
|||||||
return probabilities
|
return probabilities
|
||||||
|
|
||||||
|
|
||||||
def get_hot_numbers(probabilities: dict[int, float], top: int = 5) -> list[tuple[int, float]]:
|
def get_hot_numbers(probabilities: dict[int, float], top: int = 5) -> list[
|
||||||
|
tuple[int, float]]:
|
||||||
"""
|
"""
|
||||||
:param probabilities: A dictionary containing the probabilities
|
:param probabilities: A dictionary containing the probabilities
|
||||||
:param top: The count of hottest items to return, defaults to 5
|
:param top: The count of hottest items to return, defaults to 5
|
||||||
:returns list of tuples: A list of the hot numbers and their raw score
|
:returns list of tuples: A list of the hot numbers and their raw score
|
||||||
"""
|
"""
|
||||||
return sorted(probabilities.items(), key=lambda item: item[1], reverse=True)[:top]
|
return sorted(
|
||||||
|
probabilities.items(), key=lambda item: item[1], reverse=True,
|
||||||
|
)[:top]
|
||||||
|
|
||||||
|
|
||||||
def get_cold_numbers(probabilities: dict[int, float], bottom: int = 5) -> list[tuple[int, float]]:
|
def get_cold_numbers(probabilities: dict[int, float], bottom: int = 5) -> list[
|
||||||
|
tuple[int, float]]:
|
||||||
"""
|
"""
|
||||||
:param probabilities: A dictionary containing the probabilities
|
:param probabilities: A dictionary containing the probabilities
|
||||||
:param bottom: The count of coldest items to return, defaults to 5
|
:param bottom: The count of coldest items to return, defaults to 5
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
"""
|
"""
|
||||||
collect.py
|
collect.py
|
||||||
|
|
||||||
Functions for collecting data for insertion into the databse or pulling data from the database for analysis
|
Functions for collecting data for insertion into the databse or pulling
|
||||||
|
data from the database for analysis
|
||||||
"""
|
"""
|
||||||
from datetime import datetime, timedelta
|
from datetime import datetime, timedelta
|
||||||
from time import sleep
|
from time import sleep
|
||||||
@@ -9,10 +10,10 @@ from time import sleep
|
|||||||
from sqlalchemy import func
|
from sqlalchemy import func
|
||||||
from sqlalchemy.exc import IntegrityError
|
from sqlalchemy.exc import IntegrityError
|
||||||
|
|
||||||
from data.database import Base, dal
|
|
||||||
from lottery_predictor.config import GAME_INFO, PROJECT_VARIABLES
|
|
||||||
import util.drawing as drawutil
|
import util.drawing as drawutil
|
||||||
import util.scrape as scrapeutil
|
import util.scrape as scrapeutil
|
||||||
|
from data.database import Base, dal
|
||||||
|
from lottery_predictor.config import GAME_INFO, PROJECT_VARIABLES
|
||||||
|
|
||||||
|
|
||||||
def get_record_count(game: str) -> int | None:
|
def get_record_count(game: str) -> int | None:
|
||||||
@@ -26,7 +27,8 @@ def get_record_count(game: str) -> int | None:
|
|||||||
dal.connect()
|
dal.connect()
|
||||||
session = dal.Session()
|
session = dal.Session()
|
||||||
target_table = Base.metadata.tables.get(game_dict['db_table_name'])
|
target_table = Base.metadata.tables.get(game_dict['db_table_name'])
|
||||||
return session.query(func.count(target_table.columns.draw_date)).first()[0]
|
return \
|
||||||
|
session.query(func.count(target_table.columns.draw_date)).first()[0]
|
||||||
else:
|
else:
|
||||||
raise ValueError('An invalid table name was specified.')
|
raise ValueError('An invalid table name was specified.')
|
||||||
|
|
||||||
@@ -42,7 +44,8 @@ def get_recent_draw_date(game: str) -> datetime | None:
|
|||||||
dal.connect()
|
dal.connect()
|
||||||
session = dal.Session()
|
session = dal.Session()
|
||||||
target_table = Base.metadata.tables.get(game_dict['db_table_name'])
|
target_table = Base.metadata.tables.get(game_dict['db_table_name'])
|
||||||
return session.query(func.max(target_table.columns.draw_date)).first()[0]
|
return session.query(func.max(target_table.columns.draw_date)).first()[
|
||||||
|
0]
|
||||||
else:
|
else:
|
||||||
raise ValueError('An invalid table name was specified.')
|
raise ValueError('An invalid table name was specified.')
|
||||||
|
|
||||||
@@ -67,20 +70,39 @@ def get_missing_records(game: str) -> int:
|
|||||||
record_count = get_record_count(game=game)
|
record_count = get_record_count(game=game)
|
||||||
target_game = game_dict['game_name']
|
target_game = game_dict['game_name']
|
||||||
end_year = datetime.today().year + 1
|
end_year = datetime.today().year + 1
|
||||||
recent_draw_date = (get_recent_draw_date(game=game) + timedelta(days=1)).strftime(date_format)
|
recent_draw_date = (get_recent_draw_date(game=game) + timedelta(
|
||||||
following_draw_date = datetime.strptime(drawutil.get_next_draw_date(game=target_game,
|
days=1,
|
||||||
from_date=recent_draw_date), date_format)
|
)).strftime(
|
||||||
start_year = game_dict['inception_year'] if record_count == 0 else following_draw_date.year
|
date_format,
|
||||||
check_date = datetime.strptime(drawutil.get_previous_draw_date(game=target_game, from_date=
|
)
|
||||||
drawutil.get_next_draw_date(game=target_game)), date_format).date()
|
following_draw_date = datetime.strptime(
|
||||||
|
drawutil.get_next_draw_date(
|
||||||
|
game=target_game,
|
||||||
|
from_date=recent_draw_date,
|
||||||
|
), date_format,
|
||||||
|
)
|
||||||
|
start_year = game_dict[
|
||||||
|
'inception_year'] if record_count == 0 else following_draw_date.year
|
||||||
|
check_date = datetime.strptime(
|
||||||
|
drawutil.get_previous_draw_date(
|
||||||
|
game=target_game, from_date=
|
||||||
|
drawutil.get_next_draw_date(game=target_game),
|
||||||
|
), date_format,
|
||||||
|
).date()
|
||||||
|
|
||||||
if session.query(target_table).filter_by(draw_date=check_date).first() is None:
|
if session.query(target_table).filter_by(
|
||||||
|
draw_date=check_date,
|
||||||
|
).first() is None:
|
||||||
# loop over the range of years and insert missing records
|
# loop over the range of years and insert missing records
|
||||||
for year in range(start_year, end_year):
|
for year in range(start_year, end_year):
|
||||||
scrape_data = scrapeutil.scrape_game_history(game=target_game, year=year)
|
scrape_data = scrapeutil.scrape_game_history(
|
||||||
|
game=target_game, year=year,
|
||||||
|
)
|
||||||
# convert and insert records, discarding duplicate dates
|
# convert and insert records, discarding duplicate dates
|
||||||
for draw_date, draw_info in scrape_data.items():
|
for draw_date, draw_info in scrape_data.items():
|
||||||
record = game_dict['record_type'](draw_date=draw_date, draw_result=draw_info)
|
record = game_dict['record_type'](
|
||||||
|
draw_date=draw_date, draw_result=draw_info,
|
||||||
|
)
|
||||||
try:
|
try:
|
||||||
session.add(record)
|
session.add(record)
|
||||||
session.commit()
|
session.commit()
|
||||||
@@ -88,7 +110,10 @@ def get_missing_records(game: str) -> int:
|
|||||||
except IntegrityError:
|
except IntegrityError:
|
||||||
session.rollback()
|
session.rollback()
|
||||||
if year != end_year - 1:
|
if year != end_year - 1:
|
||||||
sleep(30) # sleep between calls to the site for data to avoid being blocked
|
sleep(
|
||||||
|
30,
|
||||||
|
) # sleep between calls to the site for data to
|
||||||
|
# avoid being blocked
|
||||||
|
|
||||||
return insert_count
|
return insert_count
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -1,8 +1,9 @@
|
|||||||
from data.database import MegaMillionsDraw, PowerballDraw
|
from data.database import MegaMillionsDraw, PowerballDraw
|
||||||
from util.drawing import get_powerball_object, get_mega_millions_object
|
from util.drawing import get_mega_millions_object, get_powerball_object
|
||||||
from util.environment import load_environment_variables
|
from util.environment import load_environment_variables
|
||||||
from util.scrape import project_variables
|
from util.scrape import project_variables
|
||||||
|
|
||||||
|
|
||||||
PROJECT_VARIABLES = load_environment_variables()
|
PROJECT_VARIABLES = load_environment_variables()
|
||||||
|
|
||||||
RANDOM_SEED = 42
|
RANDOM_SEED = 42
|
||||||
@@ -13,10 +14,16 @@ GAME_INFO = {
|
|||||||
'db_table_name': 'mega_millions_draws',
|
'db_table_name': 'mega_millions_draws',
|
||||||
'inception_year': int(project_variables["LP_MEGA_MILLIONS_INCEPTION"]),
|
'inception_year': int(project_variables["LP_MEGA_MILLIONS_INCEPTION"]),
|
||||||
'rule_change': project_variables["LP_MEGA_MILLIONS_RULE_CHANGE_DATE"],
|
'rule_change': project_variables["LP_MEGA_MILLIONS_RULE_CHANGE_DATE"],
|
||||||
'max_game_ball': int(project_variables["LP_MEGA_MILLIONS_MAX_MEGA_BALL"]),
|
'max_game_ball': int(
|
||||||
'max_main_ball': int(project_variables["LP_MEGA_MILLIONS_MAX_MAIN_BALL"]),
|
project_variables["LP_MEGA_MILLIONS_MAX_MEGA_BALL"],
|
||||||
|
),
|
||||||
|
'max_main_ball': int(
|
||||||
|
project_variables["LP_MEGA_MILLIONS_MAX_MAIN_BALL"],
|
||||||
|
),
|
||||||
|
'main_count': 5,
|
||||||
|
'game_ball_name': 'Mega Ball',
|
||||||
'scrape_name': 'mega-millions',
|
'scrape_name': 'mega-millions',
|
||||||
'object_function': get_mega_millions_object
|
'object_function': get_mega_millions_object,
|
||||||
},
|
},
|
||||||
'Powerball': {
|
'Powerball': {
|
||||||
'game_name': 'powerball',
|
'game_name': 'powerball',
|
||||||
@@ -26,7 +33,9 @@ GAME_INFO = {
|
|||||||
'rule_change': project_variables["LP_POWERBALL_RULE_CHANGE_DATE"],
|
'rule_change': project_variables["LP_POWERBALL_RULE_CHANGE_DATE"],
|
||||||
'max_game_ball': int(project_variables["LP_POWERBALL_MAX_MAIN_BALL"]),
|
'max_game_ball': int(project_variables["LP_POWERBALL_MAX_MAIN_BALL"]),
|
||||||
'max_main_ball': int(project_variables["LP_POWERBALL_MAX_POWERBALL"]),
|
'max_main_ball': int(project_variables["LP_POWERBALL_MAX_POWERBALL"]),
|
||||||
|
'main_count': 5,
|
||||||
|
'game_ball_name': 'Powerball',
|
||||||
'scrape_name': 'powerball',
|
'scrape_name': 'powerball',
|
||||||
'object_function': get_powerball_object
|
'object_function': get_powerball_object,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
@@ -1,12 +1,15 @@
|
|||||||
import random
|
import random
|
||||||
|
|
||||||
|
|
||||||
def generate_random_ticket(max_main: int, max_game: int, num_main: int = 5) -> tuple[list[int], int]:
|
def generate_random_ticket(max_main: int, max_game: int, num_main: int = 5) -> \
|
||||||
|
tuple[list[int], int]:
|
||||||
"""
|
"""
|
||||||
Generate a random lottery ticket.
|
Generate a random lottery ticket.
|
||||||
|
|
||||||
:param max_main: The maximum number in the range to choose from for main game balls
|
:param max_main: The maximum number in the range to choose from for main
|
||||||
:param max_game: The maximum number in the range to choose from for the game ball
|
game balls
|
||||||
|
:param max_game: The maximum number in the range to choose from for the
|
||||||
|
game ball
|
||||||
:param num_main: The number of numbers that can be chosen in the main field
|
:param num_main: The number of numbers that can be chosen in the main field
|
||||||
|
|
||||||
:returns: A tuple of (main_balls, game_ball)
|
:returns: A tuple of (main_balls, game_ball)
|
||||||
|
|||||||
Reference in new issue
Block a user