118 lines
4.7 KiB
Python
118 lines
4.7 KiB
Python
from lyagushka import Lyagushka
|
|
from randonautentropy import rndo
|
|
import json
|
|
import questionary
|
|
from rich.console import Console
|
|
from rich.text import Text
|
|
from rich.progress import Progress, TextColumn, BarColumn
|
|
|
|
# Validate if a string can be converted to a float
|
|
def can_be_float(s):
|
|
try:
|
|
float(s)
|
|
return True
|
|
except ValueError:
|
|
return False
|
|
|
|
# Generate random data with a specified size and maximum value
|
|
def generate_random_data(size=1024, max_value=100):
|
|
random_data = []
|
|
# Calculate the number of bytes required to represent the max value
|
|
max_value_bytes = (max_value.bit_length() + 7) // 8
|
|
max_int_for_bytes = 2**(max_value_bytes * 8) - 1
|
|
# Define the cutoff to ensure uniform distribution
|
|
mod_cutoff = max_int_for_bytes - (max_int_for_bytes % max_value) - 1
|
|
|
|
while len(random_data) < size:
|
|
# Generate random hexadecimal data
|
|
hex_data = rndo.get(length=max_value_bytes * size)
|
|
# Process the hex data in chunks
|
|
for i in (hex_data[j:j + 2 * max_value_bytes] for j in range(0, len(hex_data), 2 * max_value_bytes)):
|
|
num = int(i, 16) # Convert hex chunk to integer
|
|
if num <= mod_cutoff:
|
|
# Add the value to random_data if within the cutoff
|
|
random_data.append(num % (max_value + 1))
|
|
# Break early if enough data is collected
|
|
if len(random_data) >= size:
|
|
break
|
|
return random_data
|
|
|
|
# Analyze and select numbers based on Z-score
|
|
def pull_number(numbers: set, top: int, amount: int, z_score: float):
|
|
|
|
# Generate and sort a dataset of random numbers
|
|
dataset = generate_random_data(3000, 999)
|
|
dataset.sort()
|
|
|
|
# Analyze the dataset using Lyagushka
|
|
zhaba = Lyagushka(dataset)
|
|
analysis_results = json.loads(zhaba.search(4.0, 30))
|
|
|
|
# Filter results for valid Z-scores
|
|
results = [obj for obj in analysis_results if obj['z_score'] is not None]
|
|
max_z_score = max(obj['z_score'] for obj in results)
|
|
|
|
for obj in results:
|
|
# Check if the object has the maximum Z-score and meets the threshold
|
|
if obj['z_score'] == max_z_score and obj['z_score'] >= z_score:
|
|
# Ensure the centroid is not an x.5 and add the scaled value
|
|
if len(numbers) < amount and (obj['centroid'] % 1 != 0.5):
|
|
numbers.add(int((obj['centroid'] / 999) * top) + 1)
|
|
return numbers
|
|
|
|
# Main function to drive the lottery draw process
|
|
def main():
|
|
console = Console()
|
|
# Display an introduction to the lottery process
|
|
console.print("\nEach lottery ball is selected by analyzing random values.\n", style="italic green")
|
|
|
|
# Get the number of lottery balls to draw
|
|
num_lotto_balls = int(questionary.text(
|
|
"Amount of balls to draw? (default: 5)",
|
|
validate=lambda val: val.isdigit() or "Please enter a valid integer.",
|
|
default="5"
|
|
).ask())
|
|
|
|
# Get the highest possible number in the lottery
|
|
highest_number = int(questionary.text(
|
|
"Amount of balls in the lottery? (default: 70)",
|
|
validate=lambda val: val.isdigit() or "Please enter a valid integer.",
|
|
default="70"
|
|
).ask())
|
|
|
|
# Get the highest number for the extra draw
|
|
highest_extra_ball = int(questionary.text(
|
|
"Amount of balls in the extra draw? (default: 25)",
|
|
validate=lambda val: val.isdigit() or "Please enter a valid integer.",
|
|
default="25"
|
|
).ask())
|
|
|
|
# Get the Z-score threshold for anomaly detection
|
|
z_score_threshold = float(questionary.text(
|
|
"Minimum Z-Score Threshold? (default: 4.0)",
|
|
validate=lambda val: can_be_float(val) or "Please enter a valid value (1.0 - 5.0).",
|
|
default="4.0"
|
|
).ask())
|
|
|
|
numbers = set()
|
|
megaball = set()
|
|
|
|
# Show a progress bar during the number drawing process
|
|
with Progress(TextColumn("[progress.description]{task.description}"), BarColumn(), transient=True) as progress:
|
|
task = progress.add_task("Drawing numbers...", total=num_lotto_balls + 1)
|
|
# Draw main lottery numbers
|
|
while len(numbers) < num_lotto_balls:
|
|
numbers = pull_number(numbers, highest_number, num_lotto_balls, z_score_threshold)
|
|
progress.update(task, completed=len(numbers))
|
|
# Draw the extra ball
|
|
while len(megaball) < 1:
|
|
megaball = pull_number(megaball, highest_extra_ball, 1, z_score_threshold)
|
|
|
|
# Display the results
|
|
console.print("\nLottery numbers:\n", style="bold green")
|
|
lottery_balls = [Text(f" {n} ", style="bold black on white") for n in sorted(numbers)]
|
|
bonus_ball = Text(f" {list(megaball)[0]} ", style="bold black on yellow")
|
|
console.print(*lottery_balls, bonus_ball, sep=" ")
|
|
|
|
if __name__ == "__main__":
|
|
main()
|