2025-01-06 18:48:10 +02:00
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
2025-01-07 21:36:46 +02:00
# Validate Z-Score
def z_thresh ( s ) :
2025-01-07 20:46:32 +02:00
try :
2025-01-07 21:36:46 +02:00
if float ( s ) > = 1.0 and float ( s ) < = 5.0 :
return True
else :
return False
2025-01-07 20:46:32 +02:00
except ValueError :
return False
2025-01-06 18:48:10 +02:00
2025-01-07 20:46:32 +02:00
# Generate random data with a specified size and maximum value
def generate_random_data ( size = 1024 , max_value = 100 ) :
2025-01-06 18:48:10 +02:00
random_data = [ ]
2025-01-07 20:46:32 +02:00
# Calculate the number of bytes required to represent the max value
2025-01-06 18:48:10 +02:00
max_value_bytes = ( max_value . bit_length ( ) + 7 ) / / 8
max_int_for_bytes = 2 * * ( max_value_bytes * 8 ) - 1
2025-01-07 20:46:32 +02:00
# Define the cutoff to ensure uniform distribution
2025-01-06 18:48:10 +02:00
mod_cutoff = max_int_for_bytes - ( max_int_for_bytes % max_value ) - 1
while len ( random_data ) < size :
2025-01-07 20:46:32 +02:00
# 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
2025-01-06 18:48:10 +02:00
return random_data
2025-01-07 20:46:32 +02:00
# 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 )
2025-01-06 18:48:10 +02:00
dataset . sort ( )
2025-01-07 20:46:32 +02:00
# Analyze the dataset using Lyagushka
2025-01-06 18:48:10 +02:00
zhaba = Lyagushka ( dataset )
2025-01-07 20:46:32 +02:00
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 )
2025-01-06 18:48:10 +02:00
return numbers
2025-01-07 20:46:32 +02:00
# Main function to drive the lottery draw process
2025-01-06 18:48:10 +02:00
def main ( ) :
2025-01-07 21:36:46 +02:00
2025-01-06 18:48:10 +02:00
console = Console ( )
2025-01-07 21:36:46 +02:00
2025-01-07 20:46:32 +02:00
# Display an introduction to the lottery process
2025-01-07 21:36:46 +02:00
description = " \n Each 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 " )
2025-01-06 18:48:10 +02:00
2025-01-07 20:46:32 +02:00
# Get the number of lottery balls to draw
num_lotto_balls = int ( questionary . text (
2025-01-06 18:48:10 +02:00
" Amount of balls to draw? (default: 5) " ,
validate = lambda val : val . isdigit ( ) or " Please enter a valid integer. " ,
default = " 5 "
2025-01-07 20:46:32 +02:00
) . ask ( ) )
2025-01-06 18:48:10 +02:00
2025-01-07 20:46:32 +02:00
# Get the highest possible number in the lottery
highest_number = int ( questionary . text (
2025-01-06 18:48:10 +02:00
" Amount of balls in the lottery? (default: 70) " ,
validate = lambda val : val . isdigit ( ) or " Please enter a valid integer. " ,
default = " 70 "
2025-01-07 20:46:32 +02:00
) . ask ( ) )
2025-01-06 18:48:10 +02:00
2025-01-07 20:46:32 +02:00
# Get the highest number for the extra draw
highest_extra_ball = int ( questionary . text (
2025-01-06 18:48:10 +02:00
" Amount of balls in the extra draw? (default: 25) " ,
validate = lambda val : val . isdigit ( ) or " Please enter a valid integer. " ,
default = " 25 "
2025-01-07 20:46:32 +02:00
) . ask ( ) )
# Get the Z-score threshold for anomaly detection
z_score_threshold = float ( questionary . text (
2025-01-07 21:36:46 +02:00
" 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 "
2025-01-07 20:46:32 +02:00
) . ask ( ) )
2025-01-06 18:48:10 +02:00
numbers = set ( )
2025-01-07 20:46:32 +02:00
megaball = set ( )
2025-01-06 18:48:10 +02:00
2025-01-07 20:46:32 +02:00
# Show a progress bar during the number drawing process
2025-01-06 18:48:10 +02:00
with Progress ( TextColumn ( " [progress.description] {task.description} " ) , BarColumn ( ) , transient = True ) as progress :
2025-01-07 20:46:32 +02:00
task = progress . add_task ( " Drawing numbers... " , total = num_lotto_balls + 1 )
# Draw main lottery numbers
2025-01-06 18:48:10 +02:00
while len ( numbers ) < num_lotto_balls :
2025-01-07 20:46:32 +02:00
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 )
2025-01-06 18:48:10 +02:00
2025-01-07 20:46:32 +02:00
# Display the results
2025-01-06 18:48:10 +02:00
console . print ( " \n Lottery 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 ( )