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 Z-Score def z_thresh(s): try: if float(s) >= 1.0 and float(s) <= 5.0: return True else: return False 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 description = "\nEach lottery ball is selected by generating hundreds of random values within the provided range. The data is analyzed to identify number clusters. The centroid values of the attractor clusters with a z-score above the set threshold are selected as lotto numbers. This process repeats until all balls are drawn. The entire method is a one-dimensional analogy to how attractor points are calculated in Randonautica.\n" console.print(description, 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: 3.0)", validate=lambda val: z_thresh(val) or "Please enter a valid value (1.0 - 5.0).", default="3.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()