import gradio as gr from huggingface_hub import whoami import os import math import pandas as pd import json from itertools import combinations import random from roulette_data import ( EVEN_MONEY, DOZENS, COLUMNS, STREETS, CORNERS, SIX_LINES, SPLITS, NEIGHBORS_EUROPEAN, LEFT_OF_ZERO_EUROPEAN, RIGHT_OF_ZERO_EUROPEAN ) # New: Initialize betting category mappings for faster lookups BETTING_MAPPINGS = {} def initialize_betting_mappings(): """Initialize a mapping of numbers to their betting categories for efficient lookups.""" global BETTING_MAPPINGS BETTING_MAPPINGS = {i: {"even_money": [], "dozens": [], "columns": [], "streets": [], "corners": [], "six_lines": [], "splits": []} for i in range(37)} # Convert lists to sets and map numbers to categories for name, numbers in EVEN_MONEY.items(): numbers_set = set(numbers) for num in numbers_set: BETTING_MAPPINGS[num]["even_money"].append(name) for name, numbers in DOZENS.items(): numbers_set = set(numbers) for num in numbers_set: BETTING_MAPPINGS[num]["dozens"].append(name) for name, numbers in COLUMNS.items(): numbers_set = set(numbers) for num in numbers_set: BETTING_MAPPINGS[num]["columns"].append(name) for name, numbers in STREETS.items(): numbers_set = set(numbers) for num in numbers_set: BETTING_MAPPINGS[num]["streets"].append(name) for name, numbers in CORNERS.items(): numbers_set = set(numbers) for num in numbers_set: BETTING_MAPPINGS[num]["corners"].append(name) for name, numbers in SIX_LINES.items(): numbers_set = set(numbers) for num in numbers_set: BETTING_MAPPINGS[num]["six_lines"].append(name) for name, numbers in SPLITS.items(): numbers_set = set(numbers) for num in numbers_set: BETTING_MAPPINGS[num]["splits"].append(name) # Line 1: Start of updated update_scores_batch function def update_scores_batch(spins): """Update scores for a batch of spins and return actions for undo.""" # UNCHANGED: Initialize action log for undo action_log = [] # CHANGED: Directly update state dictionaries and build minimal action_log for spin in spins: spin_value = int(spin) action = {"spin": spin_value, "increments": {}} # Get all betting categories for this number from precomputed mappings categories = BETTING_MAPPINGS[spin_value] # Update even money scores for name in categories["even_money"]: state.even_money_scores[name] += 1 action["increments"].setdefault("even_money_scores", {})[name] = 1 # Update dozens scores for name in categories["dozens"]: state.dozen_scores[name] += 1 action["increments"].setdefault("dozen_scores", {})[name] = 1 # Update columns scores for name in categories["columns"]: state.column_scores[name] += 1 action["increments"].setdefault("column_scores", {})[name] = 1 # Update streets scores for name in categories["streets"]: state.street_scores[name] += 1 action["increments"].setdefault("street_scores", {})[name] = 1 # Update corners scores for name in categories["corners"]: state.corner_scores[name] += 1 action["increments"].setdefault("corner_scores", {})[name] = 1 # Update six lines scores for name in categories["six_lines"]: state.six_line_scores[name] += 1 action["increments"].setdefault("six_line_scores", {})[name] = 1 # Update splits scores for name in categories["splits"]: state.split_scores[name] += 1 action["increments"].setdefault("split_scores", {})[name] = 1 # Update straight-up scores state.scores[spin_value] += 1 action["increments"].setdefault("scores", {})[spin_value] = 1 # Update side scores if spin_value in current_left_of_zero: state.side_scores["Left Side of Zero"] += 1 action["increments"].setdefault("side_scores", {})["Left Side of Zero"] = 1 if spin_value in current_right_of_zero: state.side_scores["Right Side of Zero"] += 1 action["increments"].setdefault("side_scores", {})["Right Side of Zero"] = 1 action_log.append(action) # UNCHANGED: Return the action log for undo functionality return action_log def validate_roulette_data(): """Validate that all required constants from roulette_data.py are present and correctly formatted.""" required_dicts = { "EVEN_MONEY": EVEN_MONEY, "DOZENS": DOZENS, "COLUMNS": COLUMNS, "STREETS": STREETS, "CORNERS": CORNERS, "SIX_LINES": SIX_LINES, "SPLITS": SPLITS } required_neighbors = { "NEIGHBORS_EUROPEAN": NEIGHBORS_EUROPEAN, "LEFT_OF_ZERO_EUROPEAN": LEFT_OF_ZERO_EUROPEAN, "RIGHT_OF_ZERO_EUROPEAN": RIGHT_OF_ZERO_EUROPEAN } errors = [] for name, data in required_dicts.items(): if not isinstance(data, dict): errors.append(f"{name} must be a dictionary.") continue for key, value in data.items(): if not isinstance(key, str) or not isinstance(value, (list, set, tuple)) or not all(isinstance(n, int) for n in value): errors.append(f"{name}['{key}'] must map to a list/set/tuple of integers.") for name, data in required_neighbors.items(): if name == "NEIGHBORS_EUROPEAN": if not isinstance(data, dict): errors.append(f"{name} must be a dictionary.") continue for key, value in data.items(): if not isinstance(key, int) or not isinstance(value, tuple) or len(value) != 2 or not all(isinstance(n, (int, type(None))) for n in value): errors.append(f"{name}['{key}'] must map to a tuple of two integers or None.") else: if not isinstance(data, (list, set, tuple)) or not all(isinstance(n, int) for n in data): errors.append(f"{name} must be a list/set/tuple of integers.") return errors if errors else None # In Part 1, replace the RouletteState class with the following: class RouletteState: def __init__(self): self.scores = {n: 0 for n in range(37)} self.even_money_scores = {name: 0 for name in EVEN_MONEY.keys()} self.dozen_scores = {name: 0 for name in DOZENS.keys()} self.column_scores = {name: 0 for name in COLUMNS.keys()} self.street_scores = {name: 0 for name in STREETS.keys()} self.corner_scores = {name: 0 for name in CORNERS.keys()} self.six_line_scores = {name: 0 for name in SIX_LINES.keys()} self.split_scores = {name: 0 for name in SPLITS.keys()} self.side_scores = {"Left Side of Zero": 0, "Right Side of Zero": 0} self.selected_numbers = set() self.last_spins = [] self.spin_history = [] self.casino_data = { "spins_count": 100, "hot_numbers": [], "cold_numbers": [], "even_odd": {"Even": 0.0, "Odd": 0.0}, "red_black": {"Red": 0.0, "Black": 0.0}, "low_high": {"Low": 0.0, "High": 0.0}, "dozens": {"1st Dozen": 0.0, "2nd Dozen": 0.0, "3rd Dozen": 0.0}, "columns": {"1st Column": 0.0, "2nd Column": 0.0, "3rd Column": 0.0} } self.hot_suggestions = "" self.cold_suggestions = "" self.use_casino_winners = False self.bankroll = 1000 self.initial_bankroll = 1000 self.base_unit = 10 self.stop_loss = -500 self.stop_win = 200 self.target_profit = 10 self.bet_type = "Even Money" self.progression = "Martingale" self.current_bet = self.base_unit self.next_bet = self.base_unit self.progression_state = None self.consecutive_wins = 0 self.message = f"Start with base bet of {self.base_unit} on {self.bet_type} ({self.progression})" self.status = "Active" self.status_color = "white" self.last_dozen_alert_index = -1 self.alerted_patterns = set() self.last_alerted_spins = None self.labouchere_sequence = "" self.victory_vortex_sequence = [1, 8, 11, 16, 24, 35, 52, 78, 116, 174, 260, 390, 584, 876, 1313, 1969] # --- NEW VARIABLES FOR DYNAMIC 17 ASSAULT --- self.d17_list = [] self.d17_locked = False def reset(self): use_casino_winners = self.use_casino_winners casino_data = self.casino_data.copy() self.scores = {n: 0 for n in range(37)} self.even_money_scores = {name: 0 for name in EVEN_MONEY.keys()} self.dozen_scores = {name: 0 for name in DOZENS.keys()} self.column_scores = {name: 0 for name in COLUMNS.keys()} self.street_scores = {name: 0 for name in STREETS.keys()} self.corner_scores = {name: 0 for name in CORNERS.keys()} self.six_line_scores = {name: 0 for name in SIX_LINES.keys()} self.split_scores = {name: 0 for name in SPLITS.keys()} self.side_scores = {"Left Side of Zero": 0, "Right Side of Zero": 0} self.selected_numbers = set(int(s) for s in self.last_spins if s.isdigit()) self.last_spins = [] self.spin_history = [] self.use_casino_winners = use_casino_winners self.casino_data = casino_data # Reset 17 Assault self.d17_list = [] self.d17_locked = False self.reset_progression() def calculate_aggregated_scores_for_spins(self, numbers): """Calculate Aggregated Scores for a list of numbers (simulated spins).""" even_money_scores = {name: 0 for name in EVEN_MONEY.keys()} dozen_scores = {name: 0 for name in DOZENS.keys()} column_scores = {name: 0 for name in COLUMNS.keys()} for number in numbers: if number == 0: continue for name, numbers_set in EVEN_MONEY.items(): if number in numbers_set: even_money_scores[name] += 1 for name, numbers_set in DOZENS.items(): if number in numbers_set: dozen_scores[name] += 1 for name, numbers_set in COLUMNS.items(): if number in numbers_set: column_scores[name] += 1 return even_money_scores, dozen_scores, column_scores def reset_progression(self): self.current_bet = self.base_unit self.next_bet = self.base_unit self.progression_state = None self.consecutive_wins = 0 self.is_stopped = False self.message = f"Progression reset. Start with base bet of {self.base_unit} on {self.bet_type} ({self.progression})" self.check_status() return ( self.bankroll, self.current_bet, self.next_bet, self.message, f'
No spins yet.
" # Split the spins string into a list and reverse to get the most recent first spin_list = spins.split(", ") if spins else [] spin_list = spin_list[-int(num_to_show):] if spin_list else [] # Take the last N spins if not spin_list: return "No spins yet.
" # Define colors for each number (matching the European Roulette Table) colors = { "0": "green", "1": "red", "3": "red", "5": "red", "7": "red", "9": "red", "12": "red", "14": "red", "16": "red", "18": "red", "19": "red", "21": "red", "23": "red", "25": "red", "27": "red", "30": "red", "32": "red", "34": "red", "36": "red", "2": "black", "4": "black", "6": "black", "8": "black", "10": "black", "11": "black", "13": "black", "15": "black", "17": "black", "20": "black", "22": "black", "24": "black", "26": "black", "28": "black", "29": "black", "31": "black", "33": "black", "35": "black" } # Pattern detection for consecutive colors, dozens, columns, even/odd, and high/low (only if show_trends is True) patterns_by_index = {} # Dictionary to store all patterns starting at each index if show_trends: for i in range(len(spin_list) - 2): if i >= len(spin_list): break # Check for consecutive colors if colors.get(spin_list[i], "") == colors.get(spin_list[i+1], "") == colors.get(spin_list[i+2], ""): color_name = colors.get(spin_list[i], '').capitalize() if color_name: # Ensure color_name is not empty if i not in patterns_by_index: patterns_by_index[i] = [] patterns_by_index[i].append(f"3 {color_name}s in a Row") # Check for consecutive dozens dozen_hits = [next((name for name, nums in DOZENS.items() if int(spin) in nums), None) for spin in spin_list[i:i+3]] if None not in dozen_hits and len(set(dozen_hits)) == 1: if i not in patterns_by_index: patterns_by_index[i] = [] patterns_by_index[i].append(f"{dozen_hits[0]} Streak") # Check for consecutive columns column_hits = [next((name for name, nums in COLUMNS.items() if int(spin) in nums), None) for spin in spin_list[i:i+3]] if None not in column_hits and len(set(column_hits)) == 1: if i not in patterns_by_index: patterns_by_index[i] = [] patterns_by_index[i].append(f"{column_hits[0]} Streak") # Check for consecutive even/odd even_odd_hits = [next((name for name, nums in EVEN_MONEY.items() if name in ["Even", "Odd"] and int(spin) in nums), None) for spin in spin_list[i:i+3]] if None not in even_odd_hits and len(set(even_odd_hits)) == 1: if i not in patterns_by_index: patterns_by_index[i] = [] patterns_by_index[i].append(f"3 {even_odd_hits[0]}s in a Row") # Check for consecutive high/low high_low_hits = [next((name for name, nums in EVEN_MONEY.items() if name in ["High", "Low"] and int(spin) in nums), None) for spin in spin_list[i:i+3]] if None not in high_low_hits and len(set(high_low_hits)) == 1: if i not in patterns_by_index: patterns_by_index[i] = [] patterns_by_index[i].append(f"3 {high_low_hits[0]}s in a Row") # Format each spin as a colored span html_spins = [] for i, spin in enumerate(spin_list): color = colors.get(spin.strip(), "black") # Default to black if not found # Apply flip, flash, and new-spin classes to the newest spin (last in the list) if i == len(spin_list) - 1: class_attr = f'fade-in flip flash new-spin spin-{color} {color}' else: class_attr = f'fade-in {color}' # Add all pattern badges for this spin if show_trends is True pattern_badges = "" if show_trends and i in patterns_by_index: for pattern_text in patterns_by_index[i]: pattern_badges += f'{pattern_text}' html_spins.append(f'{spin}{pattern_badges}') # Wrap the spins in a div with flexbox to enable wrapping, and add a title html_output = f'No spins yet to analyze.
' hot_cold_html += 'No spins entered.
" # CHANGED: Split and clean spins, enforce max limit raw_spins = [s.strip() for s in spins_input.split(",") if s.strip()] if len(raw_spins) > 1000: error_msg = f"Too many spins ({len(raw_spins)}). Maximum allowed is 1000." gr.Warning(error_msg) print(f"validate_spins_input: Error - {error_msg}") return "", f"{error_msg}
" # CHANGED: Batch validate spins valid_spins = [] errors = [] invalid_inputs = [] for spin in raw_spins: try: num = int(spin) if not (0 <= num <= 36): errors.append(f"'{spin}' is out of range (must be 0-36)") invalid_inputs.append(spin) else: valid_spins.append(str(num)) except ValueError: errors.append(f"'{spin}' is not a valid integer") invalid_inputs.append(spin) # CHANGED: Improved error handling and messaging if not valid_spins: error_msg = "No valid spins found:\n- " + "\n- ".join(errors) + "\nUse comma-separated integers between 0 and 36 (e.g., 5, 12, 0)." gr.Warning(error_msg) print(f"validate_spins_input: Errors - {error_msg}") return "", f"{error_msg}
" # UNCHANGED: Update state and scores state.last_spins = valid_spins state.selected_numbers = set(int(s) for s in valid_spins) action_log = update_scores_batch(valid_spins) for i, spin in enumerate(valid_spins): state.spin_history.append(action_log[i]) # UNCHANGED: Limit spin history to 100 spins if len(state.spin_history) > 100: state.spin_history.pop(0) # UNCHANGED: Generate output spins_display_value = ", ".join(valid_spins) formatted_html = format_spins_as_html(spins_display_value, 36) # Default to showing all spins # CHANGED: Detailed success logging print(f"validate_spins_input: Processed {len(valid_spins)} valid spins, spins_display_value='{spins_display_value}', time={time.time() - start_time:.3f}s") if invalid_inputs: print(f"validate_spins_input: Ignored invalid inputs: {', '.join(invalid_inputs)}") # CHANGED: Include invalid inputs in warning if present if errors: warning_msg = f"Processed {len(valid_spins)} valid spins. Invalid inputs ignored:\n- " + "\n- ".join(errors) + "\nUse integers 0-36." gr.Warning(warning_msg) print(f"validate_spins_input: Warning - {warning_msg}") return spins_display_value, formatted_html # Line 1: Start of updated add_spin function def add_spin(number, current_spins, num_to_show): import gradio as gr import time start_time = time.time() # CHANGED: Added for performance logging # CHANGED: Enhanced logging with input details print(f"add_spin: Processing number='{number}', current_spins='{current_spins}', num_to_show={num_to_show}") # CHANGED: Split and deduplicate spins numbers = [n.strip() for n in number.split(",") if n.strip()] unique_numbers = list(dict.fromkeys(numbers)) # Preserve order, remove duplicates if not unique_numbers: gr.Warning("No valid input provided. Please enter numbers between 0 and 36.") print("add_spin: No valid numbers provided.") return current_spins, current_spins, "Error: No valid numbers provided.
", update_spin_counter(), render_sides_of_zero_display() # CHANGED: Reuse validate_spins_input for validation spins_input = ", ".join(unique_numbers) spins_display_value, formatted_html = validate_spins_input(spins_input) # CHANGED: Check if validation failed if not spins_display_value: print(f"add_spin: Validation failed, returning error HTML: {formatted_html}") return current_spins, current_spins, formatted_html, update_spin_counter(), render_sides_of_zero_display() # CHANGED: Efficiently update current spins current_spins_list = current_spins.split(", ") if current_spins and current_spins.strip() else [] if current_spins_list == [""]: current_spins_list = [] # CHANGED: Append new spins only if not already processed by validate_spins_input new_spins = current_spins_list + unique_numbers new_spins_str = ", ".join(new_spins) # CHANGED: Log duplicates if any if len(unique_numbers) < len(numbers): duplicates = [n for n in numbers if numbers.count(n) > 1] print(f"add_spin: Removed duplicates: {', '.join(set(duplicates))}") # CHANGED: Log success print(f"add_spin: Added {len(unique_numbers)} spins, new_spins_str='{new_spins_str}', time={time.time() - start_time:.3f}s") # UNCHANGED: Return updated outputs return new_spins_str, new_spins_str, formatted_html, update_spin_counter(), render_sides_of_zero_display() # Line 3: Start of next function (unchanged) def clear_spins(): state.selected_numbers.clear() state.last_spins = [] state.spin_history = [] # Clear spin history as well state.side_scores = {"Left Side of Zero": 0, "Right Side of Zero": 0} # Reset side scores state.scores = {n: 0 for n in range(37)} # Reset straight-up scores return "", "", "Spins cleared successfully!", "No spins yet.
", update_spin_counter(), render_sides_of_zero_display() # In Part 1, replace save_session and load_session with: import json import tempfile import os from datetime import datetime def save_session(session_name): """ Save the current session to a JSON file with a user-specified name. Args: session_name (str): The desired name for the session file (without extension). Returns: str: Path to the saved JSON file, or None if an error occurs. """ try: # Sanitize the session name to avoid invalid characters session_name = "".join(c for c in (session_name or "") if c.isalnum() or c in ('_', '-', ' ')).strip() if not session_name: session_name = "WheelPulse_Session" # Add timestamp to ensure uniqueness timestamp = datetime.now().strftime("%Y%m%d_%H%M%S") file_name = f"{session_name}_{timestamp}.json" # Collect session data session_data = { "spins": state.last_spins, "spin_history": state.spin_history, "scores": state.scores, "even_money_scores": state.even_money_scores, "dozen_scores": state.dozen_scores, "column_scores": state.column_scores, "street_scores": state.street_scores, "corner_scores": state.corner_scores, "six_line_scores": state.six_line_scores, "split_scores": state.split_scores, "side_scores": state.side_scores, "casino_data": state.casino_data, "use_casino_winners": state.use_casino_winners } # Create a temporary file temp_dir = tempfile.gettempdir() if not os.access(temp_dir, os.W_OK): raise PermissionError(f"No write permission in temporary directory: {temp_dir}") with tempfile.NamedTemporaryFile(mode='w', suffix='.json', delete=False, encoding='utf-8', dir=temp_dir) as temp_file: json.dump(session_data, temp_file, indent=4) temp_file_path = temp_file.name # Rename the temporary file to the desired name final_path = os.path.join(temp_dir, file_name) os.rename(temp_file_path, final_path) print(f"save_session: Generated file at {final_path}") return final_path except Exception as e: print(f"save_session: Error: {str(e)}") return None def load_session(file, strategy_name, neighbours_count, strong_numbers_count, *checkbox_args): try: if file is None: return ("", "", "Please upload a session file to load.", "", "", "", "", "", "", "", "", "", "", "", create_dynamic_table(strategy_name, neighbours_count, strong_numbers_count), "") with open(file.name, "r") as f: session_data = json.load(f) # Load state data state.last_spins = session_data.get("spins", []) state.spin_history = session_data.get("spin_history", []) state.scores = session_data.get("scores", {n: 0 for n in range(37)}) state.even_money_scores = session_data.get("even_money_scores", {name: 0 for name in EVEN_MONEY.keys()}) state.dozen_scores = session_data.get("dozen_scores", {name: 0 for name in DOZENS.keys()}) state.column_scores = session_data.get("column_scores", {name: 0 for name in COLUMNS.keys()}) state.street_scores = session_data.get("street_scores", {name: 0 for name in STREETS.keys()}) state.corner_scores = session_data.get("corner_scores", {name: 0 for name in CORNERS.keys()}) state.six_line_scores = session_data.get("six_line_scores", {name: 0 for name in SIX_LINES.keys()}) state.split_scores = session_data.get("split_scores", {name: 0 for name in SPLITS.keys()}) state.side_scores = session_data.get("side_scores", {"Left Side of Zero": 0, "Right Side of Zero": 0}) state.casino_data = session_data.get("casino_data", { "spins_count": 100, "hot_numbers": [], # Load as list "cold_numbers": [], # Load as list "even_odd": {"Even": 0.0, "Odd": 0.0}, "red_black": {"Red": 0.0, "Black": 0.0}, "low_high": {"Low": 0.0, "High": 0.0}, "dozens": {"1st Dozen": 0.0, "2nd Dozen": 0.0, "3rd Dozen": 0.0}, "columns": {"1st Column": 0.0, "2nd Column": 0.0, "3rd Column": 0.0} }) state.use_casino_winners = session_data.get("use_casino_winners", False) new_spins = ", ".join(state.last_spins) spin_analysis_output = f"Session loaded successfully with {len(state.last_spins)} spins." even_money_output = "\n".join([f"{name}: {score}" for name, score in state.even_money_scores.items()]) dozens_output = "\n".join([f"{name}: {score}" for name, score in state.dozen_scores.items()]) columns_output = "\n".join([f"{name}: {score}" for name, score in state.column_scores.items()]) streets_output = "\n".join([f"{name}: {score}" for name, score in state.street_scores.items()]) corners_output = "\n".join([f"{name}: {score}" for name, score in state.corner_scores.items()]) six_lines_output = "\n".join([f"{name}: {score}" for name, score in state.six_line_scores.items()]) splits_output = "\n".join([f"{name}: {score}" for name, score in state.split_scores.items()]) sides_output = "\n".join([f"{name}: {score}" for name, score in state.side_scores.items()]) straight_up_df = pd.DataFrame(list(state.scores.items()), columns=["Number", "Score"]).sort_values(by="Score", ascending=False) straight_up_html = straight_up_df.to_html(index=False, classes="scrollable-table") top_18_df = straight_up_df[straight_up_df["Score"] > 0].head(18) top_18_html = top_18_df.to_html(index=False, classes="scrollable-table") strongest_numbers_output = ", ".join([str(n) for n, s in straight_up_df.head(3).iterrows() if s["Score"] > 0]) or "No numbers have hit yet." return ( new_spins, new_spins, spin_analysis_output, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, create_dynamic_table(strategy_name, neighbours_count, strong_numbers_count), show_strategy_recommendations(strategy_name, neighbours_count, strong_numbers_count) ) except Exception as e: print(f"load_session: Error loading session: {str(e)}") return ("", "", f"Error loading session: {str(e)}", "", "", "", "", "", "", "", "", "", "", "", create_dynamic_table(strategy_name, neighbours_count, strong_numbers_count), "") # Function to calculate statistical insights def statistical_insights(): if not state.last_spins: return "No spins to analyze yet—click some numbers first!" total_spins = len(state.last_spins) number_freq = {num: state.scores[num] for num in state.scores if state.scores[num] > 0} top_numbers = sorted(number_freq.items(), key=lambda x: x[1], reverse=True)[:5] output = [f"Total Spins: {total_spins}"] output.append("Top 5 Numbers by Hits:") for num, hits in top_numbers: output.append(f"Number {num}: {hits} hits") return "\n".join(output) # Function to create HTML table (used in analyze_spins) def create_html_table(df, title): if df.empty: return f"No data to display.
" html = f"| {col} | " for col in df.columns) + "
|---|
| {val} | " for val in row) + "
No numbers have hit yet.
" # Create the HTML table table_html = '| Hit | Left N. | Right N. | Score |
|---|---|---|---|
| {num} | {left} | {right} | {score} |
Please analyze some spins first to see highlights on the dynamic table.
" # Define casino winners if highlighting is enabled, only for non-zero data casino_winners = {"hot_numbers": set(), "cold_numbers": set(), "even_money": set(), "dozens": set(), "columns": set()} if state.use_casino_winners: casino_winners["hot_numbers"] = set(state.casino_data["hot_numbers"].keys()) casino_winners["cold_numbers"] = set(state.casino_data["cold_numbers"].keys()) if any(state.casino_data["even_odd"].values()): casino_winners["even_money"].add(max(state.casino_data["even_odd"], key=state.casino_data["even_odd"].get)) if any(state.casino_data["red_black"].values()): casino_winners["even_money"].add(max(state.casino_data["red_black"], key=state.casino_data["red_black"].get)) if any(state.casino_data["low_high"].values()): casino_winners["even_money"].add(max(state.casino_data["low_high"], key=state.casino_data["low_high"].get)) if any(state.casino_data["dozens"].values()): casino_winners["dozens"] = {max(state.casino_data["dozens"], key=state.casino_data["dozens"].get)} if any(state.casino_data["columns"].values()): casino_winners["columns"] = {max(state.casino_data["columns"], key=state.casino_data["columns"].get)} print(f"Casino Winners Set: Hot={casino_winners['hot_numbers']}, Cold={casino_winners['cold_numbers']}, Even Money={casino_winners['even_money']}, Dozens={casino_winners['dozens']}, Columns={casino_winners['columns']}") # Initialize highlights for outside bets using suggestions (for Neighbours of Strong Number strategy) suggestion_highlights = {} if suggestions: # Parse suggestions to extract recommendations best_even_money = None best_bet = None play_two_first = None play_two_second = None for key, value in suggestions.items(): if key == "best_even_money" and "(Tied with" not in value: # Extract the even money bet (e.g., "Even: 5" -> "Even") best_even_money = value.split(":")[0].strip() elif key == "best_bet" and "(Tied with" not in value: # Extract the best bet (e.g., "2nd Column: 6" -> "2nd Column") best_bet = value.split(":")[0].strip() elif key == "play_two" and "(Tied with" not in value: # Extract the two options (e.g., "Play Two Columns: 2nd Column (6) and 1st Column (2)") parts = value.split(":", 1)[1].split(" and ") play_two_first = parts[0].split("(")[0].strip() # e.g., "2nd Column" play_two_second = parts[1].split("(")[0].strip() # e.g., "1st Column" # Apply highlights based on suggestions (yellow for top tier, green for second in Play Two) if best_even_money: suggestion_highlights[best_even_money] = top_color # Yellow for Best Even Money Bet if best_bet: suggestion_highlights[best_bet] = top_color # Yellow for Best Bet if play_two_first and play_two_second: # Ensure the first option in Play Two matches the Best Bet (if present) and gets yellow if best_bet and play_two_first == best_bet: suggestion_highlights[play_two_first] = top_color # Already set to yellow else: suggestion_highlights[play_two_first] = top_color # Yellow if not already set suggestion_highlights[play_two_second] = lower_color # Green for second option table_layout = [ ["", "3", "6", "9", "12", "15", "18", "21", "24", "27", "30", "33", "36"], ["0", "2", "5", "8", "11", "14", "17", "20", "23", "26", "29", "32", "35"], ["", "1", "4", "7", "10", "13", "16", "19", "22", "25", "28", "31", "34"] ] html = '| ' else: base_color = colors.get(num, "black") highlight_color = number_highlights.get(num, base_color) if num in casino_winners["hot_numbers"]: border_style = "3px solid #FFD700" # Gold, solid for consistent glow elif num in casino_winners["cold_numbers"]: border_style = "3px solid #C0C0C0" # Silver, solid for consistent glow else: border_style = "3px solid black" text_style = "color: white; font-weight: bold; text-shadow: 1px 1px 2px rgba(0, 0, 0, 0.8);" cell_class = "hot-number has-tooltip" if num in hot_numbers else "has-tooltip" hit_count = scores.get(num, scores.get(int(num), 0) if num.isdigit() else 0) tooltip = f"Hit {hit_count} times" html += f' | {num} | ' if row_idx == 0: bg_color = suggestion_highlights.get("3rd Column", top_color if trending_column == "3rd Column" else (middle_color if second_column == "3rd Column" else "white")) border_style = "3px dashed #FFD700" if "3rd Column" in casino_winners["columns"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" # Compute column score and progress bar col_score = state.column_scores.get("3rd Column", 0) max_col_score = max(state.column_scores.values(), default=1) or 1 # Avoid division by zero fill_percentage = (col_score / max_col_score) * 100 html += f'3rd Column | ' elif row_idx == 1: bg_color = suggestion_highlights.get("2nd Column", top_color if trending_column == "2nd Column" else (middle_color if second_column == "2nd Column" else "white")) border_style = "3px dashed #FFD700" if "2nd Column" in casino_winners["columns"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" col_score = state.column_scores.get("2nd Column", 0) max_col_score = max(state.column_scores.values(), default=1) or 1 fill_percentage = (col_score / max_col_score) * 100 html += f'2nd Column | ' elif row_idx == 2: bg_color = suggestion_highlights.get("1st Column", top_color if trending_column == "1st Column" else (middle_color if second_column == "1st Column" else "white")) border_style = "3px dashed #FFD700" if "1st Column" in casino_winners["columns"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" col_score = state.column_scores.get("1st Column", 0) max_col_score = max(state.column_scores.values(), default=1) or 1 fill_percentage = (col_score / max_col_score) * 100 html += f'1st Column | ' html += "|||||||||
| ' bg_color = suggestion_highlights.get("Low", top_color if trending_even_money == "Low" else (middle_color if second_even_money == "Low" else (lower_color if third_even_money == "Low" else "white"))) border_style = "3px dashed #FFD700" if "Low" in casino_winners["even_money"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" low_score = state.even_money_scores.get("Low", 0) max_even_money_score = max(state.even_money_scores.values(), default=1) or 1 fill_percentage = (low_score / max_even_money_score) * 100 html += f' | Low (1 to 18) | ' bg_color = suggestion_highlights.get("High", top_color if trending_even_money == "High" else (middle_color if second_even_money == "High" else (lower_color if third_even_money == "High" else "white"))) border_style = "3px dashed #FFD700" if "High" in casino_winners["even_money"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" high_score = state.even_money_scores.get("High", 0) fill_percentage = (high_score / max_even_money_score) * 100 html += f'High (19 to 36) | ' html += '' html += " | ||||||||||
| ' bg_color = suggestion_highlights.get("1st Dozen", top_color if trending_dozen == "1st Dozen" else (middle_color if second_dozen == "1st Dozen" else "white")) border_style = "3px dashed #FFD700" if "1st Dozen" in casino_winners["dozens"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" dozen_score = state.dozen_scores.get("1st Dozen", 0) max_dozen_score = max(state.dozen_scores.values(), default=1) or 1 fill_percentage = (dozen_score / max_dozen_score) * 100 html += f' | 1st Dozen | ' bg_color = suggestion_highlights.get("2nd Dozen", top_color if trending_dozen == "2nd Dozen" else (middle_color if second_dozen == "2nd Dozen" else "white")) border_style = "3px dashed #FFD700" if "2nd Dozen" in casino_winners["dozens"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" dozen_score = state.dozen_scores.get("2nd Dozen", 0) fill_percentage = (dozen_score / max_dozen_score) * 100 html += f'2nd Dozen | ' bg_color = suggestion_highlights.get("3rd Dozen", top_color if trending_dozen == "3rd Dozen" else (middle_color if second_dozen == "3rd Dozen" else "white")) border_style = "3px dashed #FFD700" if "3rd Dozen" in casino_winners["dozens"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" dozen_score = state.dozen_scores.get("3rd Dozen", 0) fill_percentage = (dozen_score / max_dozen_score) * 100 html += f'3rd Dozen | ' html += '' html += " | |||||||||
| ' html += f' | ' bg_color = suggestion_highlights.get("Odd", top_color if trending_even_money == "Odd" else (middle_color if second_even_money == "Odd" else (lower_color if third_even_money == "Odd" else "white"))) border_style = "3px dashed #FFD700" if "Odd" in casino_winners["even_money"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" odd_score = state.even_money_scores.get("Odd", 0) max_even_money_score = max(state.even_money_scores.values(), default=1) or 1 fill_percentage = (odd_score / max_even_money_score) * 100 html += f' | ODD | ' bg_color = suggestion_highlights.get("Red", top_color if trending_even_money == "Red" else (middle_color if second_even_money == "Red" else (lower_color if third_even_money == "Red" else "white"))) border_style = "3px dashed #FFD700" if "Red" in casino_winners["even_money"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" red_score = state.even_money_scores.get("Red", 0) fill_percentage = (red_score / max_even_money_score) * 100 html += f'RED | ' bg_color = suggestion_highlights.get("Black", top_color if trending_even_money == "Black" else (middle_color if second_even_money == "Black" else (lower_color if third_even_money == "Black" else "white"))) border_style = "3px dashed #FFD700" if "Black" in casino_winners["even_money"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" black_score = state.even_money_scores.get("Black", 0) fill_percentage = (black_score / max_even_money_score) * 100 html += f'BLACK | ' bg_color = suggestion_highlights.get("Even", top_color if trending_even_money == "Even" else (middle_color if second_even_money == "Even" else (lower_color if third_even_money == "Even" else "white"))) border_style = "3px dashed #FFD700" if "Even" in casino_winners["even_money"] else "1px solid black" tier_class = "top-tier" if bg_color == top_color else "middle-tier" if bg_color == middle_color else "lower-tier" if bg_color == lower_color else "" even_score = state.even_money_scores.get("Even", 0) fill_percentage = (even_score / max_even_money_score) * 100 html += f'EVEN | ' html += f'' html += ' | ' html += " | ||||||
Warning: No casino data provided for highlighting. Please enter percentages for Even/Odd, Red/Black, Low/High, Dozens, or Columns.
" # Generate HTML Output output = f"{name}: " + " vs ".join( f"{v:.1f}%" if k == winner else f"{v:.1f}%" for k, v in state.casino_data[key].items() ) + f" (Winner: {winner})
" else: output += f"{name}: Not set
" for key, name, has_data in [ ("dozens", "Dozens", has_dozens), ("columns", "Columns", has_columns) ]: if has_data: winner = max(state.casino_data[key], key=state.casino_data[key].get) output += f"{name}: " + " vs ".join( f"{v:.1f}%" if k == winner else f"{v:.1f}%" for k, v in state.casino_data[key].items() ) + f" (Winner: {winner})
" else: output += f"{name}: Not set
" print(f"Generated HTML Output: {output}") return output except ValueError as e: return f"Error: {str(e)}
" except Exception as e: return f"Unexpected error parsing casino data: {str(e)}
" def reset_casino_data(): """Reset casino data to defaults and clear UI inputs.""" state.casino_data = { "spins_count": 100, "hot_numbers": {}, "cold_numbers": {}, "even_odd": {"Even": 0.0, "Odd": 0.0}, "red_black": {"Red": 0.0, "Black": 0.0}, "low_high": {"Low": 0.0, "High": 0.0}, "dozens": {"1st Dozen": 0.0, "2nd Dozen": 0.0, "3rd Dozen": 0.0}, "columns": {"1st Column": 0.0, "2nd Column": 0.0, "3rd Column": 0.0} } state.use_casino_winners = False return ( "100", # spins_count_dropdown "", # hot_numbers_input "", # cold_numbers_input "", # even_odd_input "", # red_black_input "", # low_high_input "", # dozens_input "", # columns_input False, # use_winners_checkbox "Casino data reset to defaults.
" # casino_data_output ) # Line 1: Start of create_dynamic_table function (updated) def create_dynamic_table(strategy_name=None, neighbours_count=2, strong_numbers_count=1, dozen_tracker_spins=5, top_color=None, middle_color=None, lower_color=None): try: print(f"create_dynamic_table called with strategy: {strategy_name}, neighbours_count: {neighbours_count}, strong_numbers_count: {strong_numbers_count}, dozen_tracker_spins: {dozen_tracker_spins}, top_color: {top_color}, middle_color: {middle_color}, lower_color: {lower_color}") print(f"Using casino winners: {state.use_casino_winners}, Hot Numbers: {state.casino_data['hot_numbers']}, Cold Numbers: {state.casino_data['cold_numbers']}") print("create_dynamic_table: Calculating trending sections") sorted_sections = calculate_trending_sections() print(f"create_dynamic_table: sorted_sections={sorted_sections}") # If no spins yet, initialize with default even money focus if sorted_sections is None and strategy_name == "Best Even Money Bets": print("create_dynamic_table: No spins yet, using default even money focus") trending_even_money = "Red" # Default to "Red" as an example second_even_money = "Black" third_even_money = "Even" trending_dozen = None second_dozen = None trending_column = None second_column = None number_highlights = {} top_color = top_color if top_color else "rgba(255, 255, 0, 0.5)" middle_color = middle_color if middle_color else "rgba(0, 255, 255, 0.5)" lower_color = lower_color if lower_color else "rgba(0, 255, 0, 0.5)" suggestions = None hot_numbers = [] # No hot numbers without spins else: print("create_dynamic_table: Applying strategy highlights") trending_even_money, second_even_money, third_even_money, trending_dozen, second_dozen, trending_column, second_column, number_highlights, top_color, middle_color, lower_color, suggestions = apply_strategy_highlights(strategy_name, int(dozen_tracker_spins) if strategy_name == "None" else neighbours_count, strong_numbers_count, sorted_sections, top_color, middle_color, lower_color) print(f"create_dynamic_table: Strategy highlights applied - trending_even_money={trending_even_money}, second_even_money={second_even_money}, third_even_money={third_even_money}, trending_dozen={trending_dozen}, second_dozen={second_dozen}, trending_column={trending_column}, second_column={second_column}, number_highlights={number_highlights}") # Determine hot numbers (top 5 with hits) sorted_scores = sorted(state.scores.items(), key=lambda x: x[1], reverse=True) hot_numbers = [str(num) for num, score in sorted_scores[:5] if score > 0] print(f"create_dynamic_table: Hot numbers={hot_numbers}, Scores={dict(state.scores)}") # If still no highlights and no sorted_sections, provide a default message if sorted_sections is None and not any([trending_even_money, second_even_money, third_even_money, trending_dozen, second_dozen, trending_column, second_column, number_highlights]): print("create_dynamic_table: No spins and no highlights, returning default message") return "No spins yet. Select a strategy to see default highlights.
" print("create_dynamic_table: Rendering dynamic table HTML") html = render_dynamic_table_html(trending_even_money, second_even_money, third_even_money, trending_dozen, second_dozen, trending_column, second_column, number_highlights, top_color, middle_color, lower_color, suggestions, hot_numbers, scores=state.scores) print("create_dynamic_table: Table generated successfully") return html except Exception as e: print(f"create_dynamic_table: Error: {str(e)}") raise # Re-raise for debugging # Function to get strongest numbers with neighbors def get_strongest_numbers_with_neighbors(num_count): num_count = int(num_count) straight_up_df = pd.DataFrame(list(state.scores.items()), columns=["Number", "Score"]) straight_up_df = straight_up_df[straight_up_df["Score"] > 0].sort_values(by="Score", ascending=False) if straight_up_df.empty: return "No numbers have hit yet." num_to_take = max(1, num_count // 3) top_numbers = straight_up_df["Number"].head(num_to_take).tolist() if not top_numbers: return "No strong numbers available to display." all_numbers = set() for num in top_numbers: neighbors = current_neighbors.get(num, (None, None)) left, right = neighbors all_numbers.add(num) if left is not None: all_numbers.add(left) if right is not None: all_numbers.add(right) sorted_numbers = sorted(list(all_numbers)) return f"Strongest {len(sorted_numbers)} Numbers (Sorted Lowest to Highest): {', '.join(map(str, sorted_numbers))}" # Function to analyze spins def analyze_spins(spins_input, strategy_name, neighbours_count, *checkbox_args): """Analyze the spins and return formatted results for all sections, always resetting scores.""" try: print(f"analyze_spins: Starting with spins_input='{spins_input}', strategy_name='{strategy_name}', neighbours_count={neighbours_count}, checkbox_args={checkbox_args}") # Handle empty spins case if not spins_input or not spins_input.strip(): print("analyze_spins: No spins input provided.") state.reset() # Always reset scores print("analyze_spins: Scores reset due to empty spins.") return ("Please enter at least one number (e.g., 5, 12, 0).", "", "", "", "", "", "", "", "", "", "", "", "", "", render_sides_of_zero_display()) raw_spins = [spin.strip() for spin in spins_input.split(",") if spin.strip()] spins = [] errors = [] for spin in raw_spins: try: num = int(spin) if not (0 <= num <= 36): errors.append(f"Error: '{spin}' is out of range. Use numbers between 0 and 36.") continue spins.append(str(num)) except ValueError: errors.append(f"Error: '{spin}' is not a valid number. Use whole numbers (e.g., 5, 12, 0).") continue if errors: error_msg = "\n".join(errors) print(f"analyze_spins: Errors found - {error_msg}") return (error_msg, "", "", "", "", "", "", "", "", "", "", "", "", "", render_sides_of_zero_display()) if not spins: print("analyze_spins: No valid spins found.") state.reset() # Always reset scores print("analyze_spins: Scores reset due to no valid spins.") return ("No valid numbers found. Please enter numbers like '5, 12, 0'.", "", "", "", "", "", "", "", "", "", "", "", "", "", render_sides_of_zero_display()) # Always reset scores state.reset() print("analyze_spins: Scores reset.") # Batch update scores for all spins print("analyze_spins: Updating scores batch") action_log = update_scores_batch(spins) print(f"analyze_spins: action_log={action_log}") # Update state.last_spins and spin_history state.last_spins = spins # Replace last_spins with current spins state.spin_history = action_log # Replace spin_history with current action_log # Limit spin history to 100 spins if len(state.spin_history) > 100: state.spin_history = state.spin_history[-100:] print(f"analyze_spins: Updated state.last_spins={state.last_spins}, spin_history length={len(state.spin_history)}") # Generate spin analysis output print("analyze_spins: Generating spin analysis output") spin_results = [] state.selected_numbers.clear() # Clear before rebuilding for idx, spin in enumerate(spins): spin_value = int(spin) hit_sections = [] action = action_log[idx] # Reconstruct hit sections from increments for name, increment in action["increments"].get("even_money_scores", {}).items(): if increment > 0: hit_sections.append(name) for name, increment in action["increments"].get("dozen_scores", {}).items(): if increment > 0: hit_sections.append(name) for name, increment in action["increments"].get("column_scores", {}).items(): if increment > 0: hit_sections.append(name) for name, increment in action["increments"].get("street_scores", {}).items(): if increment > 0: hit_sections.append(name) for name, increment in action["increments"].get("corner_scores", {}).items(): if increment > 0: hit_sections.append(name) for name, increment in action["increments"].get("six_line_scores", {}).items(): if increment > 0: hit_sections.append(name) for name, increment in action["increments"].get("split_scores", {}).items(): if increment > 0: hit_sections.append(name) if spin_value in action["increments"].get("scores", {}): hit_sections.append(f"Straight Up {spin}") for name, increment in action["increments"].get("side_scores", {}).items(): if increment > 0: hit_sections.append(name) # Add neighbor information if spin_value in current_neighbors: left, right = current_neighbors[spin_value] hit_sections.append(f"Left Neighbor: {left}") hit_sections.append(f"Right Neighbor: {right}") spin_results.append(f"Spin {spin} hits: {', '.join(hit_sections)}\nTotal sections hit: {len(hit_sections)}") state.selected_numbers = set(int(s) for s in state.last_spins if s.isdigit()) # Sync with last_spins spin_analysis_output = "\n".join(spin_results) print(f"analyze_spins: spin_analysis_output='{spin_analysis_output}'") even_money_output = "Even Money Bets:\n" + "\n".join(f"{name}: {score}" for name, score in state.even_money_scores.items()) print(f"analyze_spins: even_money_output='{even_money_output}'") dozens_output = "Dozens:\n" + "\n".join(f"{name}: {score}" for name, score in state.dozen_scores.items()) print(f"analyze_spins: dozens_output='{dozens_output}'") columns_output = "Columns:\n" + "\n".join(f"{name}: {score}" for name, score in state.column_scores.items()) print(f"analyze_spins: columns_output='{columns_output}'") streets_output = "Streets:\n" + "\n".join(f"{name}: {score}" for name, score in state.street_scores.items() if score > 0) print(f"analyze_spins: streets_output='{streets_output}'") corners_output = "Corners:\n" + "\n".join(f"{name}: {score}" for name, score in state.corner_scores.items() if score > 0) print(f"analyze_spins: corners_output='{corners_output}'") six_lines_output = "Double Streets:\n" + "\n".join(f"{name}: {score}" for name, score in state.six_line_scores.items() if score > 0) print(f"analyze_spins: six_lines_output='{six_lines_output}'") splits_output = "Splits:\n" if any(score > 0 for score in state.split_scores.values()) else "Splits: No hits yet.\n" splits_output += "\n".join(f"{name}: {score}" for name, score in state.split_scores.items() if score > 0) print(f"analyze_spins: splits_output='{splits_output}'") sides_output = "Sides of Zero:\n" + "\n".join(f"{name}: {score}" for name, score in state.side_scores.items()) print(f"analyze_spins: sides_output='{sides_output}'") print("analyze_spins: Creating straight_up_df") straight_up_df = pd.DataFrame(list(state.scores.items()), columns=["Number", "Score"]) straight_up_df = straight_up_df[straight_up_df["Score"] > 0].sort_values(by="Score", ascending=False) straight_up_df["Left Neighbor"] = straight_up_df["Number"].apply(lambda x: current_neighbors[x][0] if x in current_neighbors else "") straight_up_df["Right Neighbor"] = straight_up_df["Number"].apply(lambda x: current_neighbors[x][1] if x in current_neighbors else "") straight_up_html = create_html_table(straight_up_df[["Number", "Left Neighbor", "Right Neighbor", "Score"]], "Strongest Numbers") print(f"analyze_spins: straight_up_html generated") print("analyze_spins: Creating top_18_df") top_18_df = straight_up_df.head(18).sort_values(by="Number", ascending=True) numbers = top_18_df["Number"].tolist() if len(numbers) < 18: numbers.extend([""] * (18 - len(numbers))) grid_data = [numbers[i::3] for i in range(3)] top_18_html = "| {num} | ' top_18_html += "
| {num} | ' top_18_html += "
No spins yet.
", "", "", "", "", "", "", "", "", "", "", "", update_spin_counter(), render_sides_of_zero_display() def reset_strategy_dropdowns(): default_category = "Even Money Strategies" default_strategy = "Best Even Money Bets" strategy_choices = strategy_categories[default_category] return default_category, default_strategy, strategy_choices def generate_random_spins(num_spins, current_spins_display, last_spin_count): try: num_spins = int(num_spins) if num_spins <= 0: return current_spins_display, current_spins_display, "Please select a number of spins greater than 0.", update_spin_counter(), render_sides_of_zero_display() new_spins = [str(random.randint(0, 36)) for _ in range(num_spins)] # Update scores for the new spins update_scores_batch(new_spins) if current_spins_display and current_spins_display.strip(): current_spins = current_spins_display.split(", ") updated_spins = current_spins + new_spins else: updated_spins = new_spins # Update state.last_spins state.last_spins = updated_spins # Replace the list entirely spins_text = ", ".join(updated_spins) print(f"generate_random_spins: Setting spins_textbox to '{spins_text}'") return spins_text, spins_text, f"Generated {num_spins} random spins: {', '.join(new_spins)}", update_spin_counter(), render_sides_of_zero_display() except ValueError: print("generate_random_spins: Invalid number of spins entered.") return current_spins_display, current_spins_display, "Please enter a valid number of spins.", update_spin_counter(), render_sides_of_zero_display() except Exception as e: print(f"generate_random_spins: Unexpected error: {str(e)}") return current_spins_display, current_spins_display, f"Error generating spins: {str(e)}", update_spin_counter(), render_sides_of_zero_display() # Strategy functions def best_even_money_bets(): recommendations = [] sorted_even_money = sorted(state.even_money_scores.items(), key=lambda x: x[1], reverse=True) even_money_hits = [item for item in sorted_even_money if item[1] > 0] if not even_money_hits: recommendations.append("Best Even Money Bets: No hits yet.") return "\n".join(recommendations) # Collect the top 3 bets, including ties top_bets = [] scores_seen = set() for name, score in sorted_even_money: if len(top_bets) < 3 or score in scores_seen: top_bets.append((name, score)) scores_seen.add(score) else: break # Display the top 3 bets recommendations.append("Best Even Money Bets (Top 3):") for i, (name, score) in enumerate(top_bets[:3], 1): recommendations.append(f"{i}. {name}: {score}") # Check for ties among the top 3 positions if len(top_bets) > 1: # Check for ties at the 1st position first_score = top_bets[0][1] tied_first = [name for name, score in top_bets if score == first_score] if len(tied_first) > 1: recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_first)} with score {first_score}") # Check for ties at the 2nd position if len(top_bets) > 1: second_score = top_bets[1][1] tied_second = [name for name, score in top_bets if score == second_score] if len(tied_second) > 1: recommendations.append(f"Note: Tie for 2nd place among {', '.join(tied_second)} with score {second_score}") # Check for ties at the 3rd position if len(top_bets) > 2: third_score = top_bets[2][1] tied_third = [name for name, score in top_bets if score == third_score] if len(tied_third) > 1: recommendations.append(f"Note: Tie for 3rd place among {', '.join(tied_third)} with score {third_score}") return "\n".join(recommendations) def hot_bet_strategy(): recommendations = [] sorted_even_money = sorted(state.even_money_scores.items(), key=lambda x: x[1], reverse=True) even_money_hits = [item for item in sorted_even_money if item[1] > 0] if even_money_hits: recommendations.append("Even Money (Top 2):") for i, (name, score) in enumerate(even_money_hits[:2], 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("Even Money: No hits yet.") sorted_dozens = sorted(state.dozen_scores.items(), key=lambda x: x[1], reverse=True) dozens_hits = [item for item in sorted_dozens if item[1] > 0] if dozens_hits: recommendations.append("\nDozens (Top 2):") for i, (name, score) in enumerate(dozens_hits[:2], 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("\nDozens: No hits yet.") sorted_columns = sorted(state.column_scores.items(), key=lambda x: x[1], reverse=True) columns_hits = [item for item in sorted_columns if item[1] > 0] if columns_hits: recommendations.append("\nColumns (Top 2):") for i, (name, score) in enumerate(columns_hits[:2], 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("\nColumns: No hits yet.") sorted_streets = sorted(state.street_scores.items(), key=lambda x: x[1], reverse=True) streets_hits = [item for item in sorted_streets if item[1] > 0] if streets_hits: recommendations.append("\nStreets (Ranked):") for i, (name, score) in enumerate(streets_hits, 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("\nStreets: No hits yet.") sorted_corners = sorted(state.corner_scores.items(), key=lambda x: x[1], reverse=True) corners_hits = [item for item in sorted_corners if item[1] > 0] if corners_hits: recommendations.append("\nCorners (Ranked):") for i, (name, score) in enumerate(corners_hits, 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("\nCorners: No hits yet.") sorted_six_lines = sorted(state.six_line_scores.items(), key=lambda x: x[1], reverse=True) six_lines_hits = [item for item in sorted_six_lines if item[1] > 0] if six_lines_hits: recommendations.append("\nDouble Streets (Ranked):") for i, (name, score) in enumerate(six_lines_hits, 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("\nDouble Streets: No hits yet.") sorted_splits = sorted(state.split_scores.items(), key=lambda x: x[1], reverse=True) splits_hits = [item for item in sorted_splits if item[1] > 0] if splits_hits: recommendations.append("\nSplits (Ranked):") for i, (name, score) in enumerate(splits_hits, 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("\nSplits: No hits yet.") sorted_sides = sorted(state.side_scores.items(), key=lambda x: x[1], reverse=True) sides_hits = [item for item in sorted_sides if item[1] > 0] if sides_hits: recommendations.append("\nSides of Zero:") recommendations.append(f"1. {sides_hits[0][0]}: {sides_hits[0][1]}") else: recommendations.append("\nSides of Zero: No hits yet.") sorted_numbers = sorted(state.scores.items(), key=lambda x: x[1], reverse=True) numbers_hits = [item for item in sorted_numbers if item[1] > 0] if numbers_hits: number_best = numbers_hits[0] left_neighbor, right_neighbor = current_neighbors[number_best[0]] recommendations.append(f"\nStrongest Number: {number_best[0]} (Score: {number_best[1]}) with neighbors {left_neighbor} and {right_neighbor}") else: recommendations.append("\nStrongest Number: No hits yet.") return "\n".join(recommendations) # Function for Cold Bet Strategy def cold_bet_strategy(): recommendations = [] sorted_even_money = sorted(state.even_money_scores.items(), key=lambda x: x[1]) even_money_non_hits = [item for item in sorted_even_money if item[1] == 0] even_money_hits = [item for item in sorted_even_money if item[1] > 0] if even_money_non_hits: recommendations.append("Even Money (Not Hit):") recommendationsече.append(", ".join(item[0] for item in even_money_non_hits)) if even_money_hits: recommendations.append("\nEven Money (Lowest Scores):") for i, (name, score) in enumerate(even_money_hits[:2], 1): recommendations.append(f"{i}. {name}: {score}") sorted_dozens = sorted(state.dozen_scores.items(), key=lambda x: x[1]) dozens_non_hits = [item for item in sorted_dozens if item[1] == 0] dozens_hits = [item for item in sorted_dozens if item[1] > 0] if dozens_non_hits: recommendations.append("\nDozens (Not Hit):") recommendations.append(", ".join(item[0] for item in dozens_non_hits)) if dozens_hits: recommendations.append("\nDozens (Lowest Scores):") for i, (name, score) in enumerate(dozens_hits[:2], 1): recommendations.append(f"{i}. {name}: {score}") sorted_columns = sorted(state.column_scores.items(), key=lambda x: x[1]) columns_non_hits = [item for item in sorted_columns if item[1] == 0] columns_hits = [item for item in sorted_columns if item[1] > 0] if columns_non_hits: recommendations.append("\nColumns (Not Hit):") recommendations.append(", ".join(item[0] for item in columns_non_hits)) if columns_hits: recommendations.append("\nColumns (Lowest Scores):") for i, (name, score) in enumerate(columns_hits[:2], 1): recommendations.append(f"{i}. {name}: {score}") sorted_streets = sorted(state.street_scores.items(), key=lambda x: x[1]) streets_non_hits = [item for item in sorted_streets if item[1] == 0] streets_hits = [item for item in sorted_streets if item[1] > 0] if streets_non_hits: recommendations.append("\nStreets (Not Hit):") recommendations.append(", ".join(item[0] for item in streets_non_hits)) if streets_hits: recommendations.append("\nStreets (Lowest Scores):") for i, (name, score) in enumerate(streets_hits[:3], 1): recommendations.append(f"{i}. {name}: {score}") sorted_corners = sorted(state.corner_scores.items(), key=lambda x: x[1]) corners_non_hits = [item for item in sorted_corners if item[1] == 0] corners_hits = [item for item in sorted_corners if item[1] > 0] if corners_non_hits: recommendations.append("\nCorners (Not Hit):") recommendations.append(", ".join(item[0] for item in corners_non_hits)) if corners_hits: recommendations.append("\nCorners (Lowest Scores):") for i, (name, score) in enumerate(corners_hits[:3], 1): recommendations.append(f"{i}. {name}: {score}") sorted_six_lines = sorted(state.six_line_scores.items(), key=lambda x: x[1]) six_lines_non_hits = [item for item in sorted_six_lines if item[1] == 0] six_lines_hits = [item for item in sorted_six_lines if item[1] > 0] if six_lines_non_hits: recommendations.append("\nDouble Streets (Not Hit):") recommendations.append(", ".join(item[0] for item in six_lines_non_hits)) if six_lines_hits: recommendations.append("\nDouble Streets (Lowest Scores):") for i, (name, score) in enumerate(six_lines_hits[:3], 1): recommendations.append(f"{i}. {name}: {score}") sorted_splits = sorted(state.split_scores.items(), key=lambda x: x[1]) splits_non_hits = [item for item in sorted_splits if item[1] == 0] splits_hits = [item for item in sorted_splits if item[1] > 0] if splits_non_hits: recommendations.append("\nSplits (Not Hit):") recommendations.append(", ".join(item[0] for item in splits_non_hits)) if splits_hits: recommendations.append("\nSplits (Lowest Scores):") for i, (name, score) in enumerate(splits_hits[:3], 1): recommendations.append(f"{i}. {name}: {score}") sorted_sides = sorted(state.side_scores.items(), key=lambda x: x[1]) sides_non_hits = [item for item in sorted_sides if item[1] == 0] sides_hits = [item for item in sorted_sides if item[1] > 0] if sides_non_hits: recommendations.append("\nSides of Zero (Not Hit):") recommendations.append(", ".join(item[0] for item in sides_non_hits)) if sides_hits: recommendations.append("\nSides of Zero (Lowest Score):") recommendations.append(f"1. {sides_hits[0][0]}: {sides_hits[0][1]}") sorted_numbers = sorted(state.scores.items(), key=lambda x: x[1]) numbers_non_hits = [item for item in sorted_numbers if item[1] == 0] numbers_hits = [item for item in sorted_numbers if item[1] > 0] if numbers_non_hits: recommendations.append("\nNumbers (Not Hit):") recommendations.append(", ".join(str(item[0]) for item in numbers_non_hits)) if numbers_hits: number_worst = numbers_hits[0] left_neighbor, right_neighbor = current_neighbors[number_worst[0]] recommendations.append(f"\nColdest Number: {number_worst[0]} (Score: {number_worst[1]}) with neighbors {left_neighbor} and {right_neighbor}") return "\n".join(recommendations) def best_dozens(): recommendations = [] sorted_dozens = sorted(state.dozen_scores.items(), key=lambda x: x[1], reverse=True) dozens_hits = [item for item in sorted_dozens if item[1] > 0] if dozens_hits: recommendations.append("Best Dozens (Top 2):") for i, (name, score) in enumerate(dozens_hits[:2], 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("Best Dozens: No hits yet.") return "\n".join(recommendations) def best_columns(): recommendations = [] sorted_columns = sorted(state.column_scores.items(), key=lambda x: x[1], reverse=True) columns_hits = [item for item in sorted_columns if item[1] > 0] if columns_hits: recommendations.append("Best Columns (Top 2):") for i, (name, score) in enumerate(columns_hits[:2], 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("Best Columns: No hits yet.") return "\n".join(recommendations) def fibonacci_strategy(): recommendations = [] sorted_dozens = sorted(state.dozen_scores.items(), key=lambda x: x[1], reverse=True) dozens_hits = [item for item in sorted_dozens if item[1] > 0] sorted_columns = sorted(state.column_scores.items(), key=lambda x: x[1], reverse=True) columns_hits = [item for item in sorted_columns if item[1] > 0] if not dozens_hits and not columns_hits: recommendations.append("Fibonacci Strategy: No hits in Dozens or Columns yet.") return "\n".join(recommendations) best_dozen_score = dozens_hits[0][1] if dozens_hits else 0 best_column_score = columns_hits[0][1] if columns_hits else 0 if best_dozen_score > best_column_score: # Dozens wins: show top two dozens recommendations.append("Best Category: Dozens") top_dozens = [] scores_seen = set() for name, score in sorted_dozens: if len(top_dozens) < 2 or score in scores_seen: top_dozens.append((name, score)) scores_seen.add(score) else: break for i, (name, score) in enumerate(top_dozens[:2], 1): recommendations.append(f"Best Dozen {i}: {name} (Score: {score})") # Check for ties among the top two if len(top_dozens) > 1 and top_dozens[0][1] == top_dozens[1][1]: tied_dozens = [name for name, score in top_dozens if score == top_dozens[0][1]] recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_dozens)} with score {top_dozens[0][1]}") elif best_column_score > best_dozen_score: # Columns wins: show top two columns recommendations.append("Best Category: Columns") top_columns = [] scores_seen = set() for name, score in sorted_columns: if len(top_columns) < 2 or score in scores_seen: top_columns.append((name, score)) scores_seen.add(score) else: break for i, (name, score) in enumerate(top_columns[:2], 1): recommendations.append(f"Best Column {i}: {name} (Score: {score})") # Check for ties among the top two if len(top_columns) > 1 and top_columns[0][1] == top_columns[1][1]: tied_columns = [name for name, score in top_columns if score == top_columns[0][1]] recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_columns)} with score {top_columns[0][1]}") else: # Tie between Dozens and Columns: show both top options recommendations.append(f"Best Category (Tied): Dozens and Columns (Score: {best_dozen_score})") if dozens_hits: top_dozens = [] scores_seen = set() for name, score in sorted_dozens: if len(top_dozens) < 2 or score in scores_seen: top_dozens.append((name, score)) scores_seen.add(score) else: break for i, (name, score) in enumerate(top_dozens[:2], 1): recommendations.append(f"Best Dozen {i}: {name} (Score: {score})") if len(top_dozens) > 1 and top_dozens[0][1] == top_dozens[1][1]: tied_dozens = [name for name, score in top_dozens if score == top_dozens[0][1]] recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_dozens)} with score {top_dozens[0][1]}") if columns_hits: top_columns = [] scores_seen = set() for name, score in sorted_columns: if len(top_columns) < 2 or score in scores_seen: top_columns.append((name, score)) scores_seen.add(score) else: break for i, (name, score) in enumerate(top_columns[:2], 1): recommendations.append(f"Best Column {i}: {name} (Score: {score})") if len(top_columns) > 1 and top_columns[0][1] == top_columns[1][1]: tied_columns = [name for name, score in top_columns if score == top_columns[0][1]] recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_columns)} with score {top_columns[0][1]}") return "\n".join(recommendations) def best_streets(): recommendations = [] sorted_streets = sorted(state.street_scores.items(), key=lambda x: x[1], reverse=True) streets_hits = [item for item in sorted_streets if item[1] > 0] if not streets_hits: recommendations.append("Best Streets: No hits yet.") return "\n".join(recommendations) recommendations.append("Top 3 Streets:") for i, (name, score) in enumerate(streets_hits[:3], 1): recommendations.append(f"{i}. {name}: {score}") recommendations.append("\nTop 6 Streets:") for i, (name, score) in enumerate(streets_hits[:6], 1): recommendations.append(f"{i}. {name}: {score}") return "\n".join(recommendations) def best_double_streets(): recommendations = [] sorted_six_lines = sorted(state.six_line_scores.items(), key=lambda x: x[1], reverse=True) six_lines_hits = [item for item in sorted_six_lines if item[1] > 0] if not six_lines_hits: recommendations.append("Best Double Streets: No hits yet.") return "\n".join(recommendations) recommendations.append("Double Streets (Ranked):") for i, (name, score) in enumerate(six_lines_hits, 1): recommendations.append(f"{i}. {name}: {score}") return "\n".join(recommendations) def best_corners(): recommendations = [] sorted_corners = sorted(state.corner_scores.items(), key=lambda x: x[1], reverse=True) corners_hits = [item for item in sorted_corners if item[1] > 0] if not corners_hits: recommendations.append("Best Corners: No hits yet.") return "\n".join(recommendations) recommendations.append("Corners (Ranked):") for i, (name, score) in enumerate(corners_hits, 1): recommendations.append(f"{i}. {name}: {score}") return "\n".join(recommendations) def best_splits(): recommendations = [] sorted_splits = sorted(state.split_scores.items(), key=lambda x: x[1], reverse=True) splits_hits = [item for item in sorted_splits if item[1] > 0] if not splits_hits: recommendations.append("Best Splits: No hits yet.") return "\n".join(recommendations) recommendations.append("Splits (Ranked):") for i, (name, score) in enumerate(splits_hits, 1): recommendations.append(f"{i}. {name}: {score}") return "\n".join(recommendations) def best_dozens_and_streets(): recommendations = [] sorted_dozens = sorted(state.dozen_scores.items(), key=lambda x: x[1], reverse=True) dozens_hits = [item for item in sorted_dozens if item[1] > 0] if dozens_hits: recommendations.append("Best Dozens (Top 2):") for i, (name, score) in enumerate(dozens_hits[:2], 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("Best Dozens: No hits yet.") sorted_streets = sorted(state.street_scores.items(), key=lambda x: x[1], reverse=True) streets_hits = [item for item in sorted_streets if item[1] > 0] if streets_hits: recommendations.append("\nTop 3 Streets (Yellow):") for i, (name, score) in enumerate(streets_hits[:3], 1): recommendations.append(f"{i}. {name}: {score}") recommendations.append("\nMiddle 3 Streets (Cyan):") for i, (name, score) in enumerate(streets_hits[3:6], 1): recommendations.append(f"{i}. {name}: {score}") recommendations.append("\nBottom 3 Streets (Green):") for i, (name, score) in enumerate(streets_hits[6:9], 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("\nBest Streets: No hits yet.") return "\n".join(recommendations) def best_columns_and_streets(): recommendations = [] sorted_columns = sorted(state.column_scores.items(), key=lambda x: x[1], reverse=True) columns_hits = [item for item in sorted_columns if item[1] > 0] if columns_hits: recommendations.append("Best Columns (Top 2):") for i, (name, score) in enumerate(columns_hits[:2], 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("Best Columns: No hits yet.") sorted_streets = sorted(state.street_scores.items(), key=lambda x: x[1], reverse=True) streets_hits = [item for item in sorted_streets if item[1] > 0] if streets_hits: recommendations.append("\nTop 3 Streets (Yellow):") for i, (name, score) in enumerate(streets_hits[:3], 1): recommendations.append(f"{i}. {name}: {score}") recommendations.append("\nMiddle 3 Streets (Cyan):") for i, (name, score) in enumerate(streets_hits[3:6], 1): recommendations.append(f"{i}. {name}: {score}") recommendations.append("\nBottom 3 Streets (Green):") for i, (name, score) in enumerate(streets_hits[6:9], 1): recommendations.append(f"{i}. {name}: {score}") else: recommendations.append("\nBest Streets: No hits yet.") return "\n".join(recommendations) def non_overlapping_double_street_strategy(): non_overlapping_sets = [ ["1ST D.STREET – 1, 4", "3RD D.STREET – 7, 10", "5TH D.STREET – 13, 16", "7TH D.STREET – 19, 22", "9TH D.STREET – 25, 28"], ["2ND D.STREET – 4, 7", "4TH D.STREET – 10, 13", "6TH D.STREET – 16, 19", "8TH D.STREET – 22, 25", "10TH D.STREET – 28, 31"] ] set_scores = [] for idx, non_overlapping_set in enumerate(non_overlapping_sets): total_score = sum(state.six_line_scores[name] for name in non_overlapping_set) set_scores.append((idx, total_score, non_overlapping_set)) best_set = max(set_scores, key=lambda x: x[1]) best_set_idx, best_set_score, best_set_streets = best_set sorted_streets = sorted(best_set_streets, key=lambda name: state.six_line_scores[name], reverse=True) recommendations = [] recommendations.append(f"Non-Overlapping Double Streets Strategy (Set {best_set_idx + 1} with Total Score: {best_set_score})") recommendations.append("Hottest Non-Overlapping Double Streets (Sorted by Hotness):") for i, name in enumerate(sorted_streets, 1): score = state.six_line_scores[name] recommendations.append(f"{i}. {name}: {score}") return "\n".join(recommendations) def non_overlapping_corner_strategy(): non_overlapping_sets = [ ["1ST CORNER – 1, 2, 4, 5", "5TH CORNER – 7, 8, 10, 11", "9TH CORNER – 13, 14, 16, 17", "13TH CORNER – 19, 20, 22, 23", "17TH CORNER – 25, 26, 28, 29", "21ST CORNER – 31, 32, 34, 35"], ["2ND CORNER – 2, 3, 5, 6", "6TH CORNER – 8, 9, 11, 12", "10TH CORNER – 14, 15, 17, 18", "14TH CORNER – 20, 21, 23, 24", "18TH CORNER – 26, 27, 29, 30", "22ND CORNER – 32, 33, 35, 36"] ] set_scores = [] for idx, non_overlapping_set in enumerate(non_overlapping_sets): total_score = sum(state.corner_scores[name] for name in non_overlapping_set) set_scores.append((idx, total_score, non_overlapping_set)) best_set = max(set_scores, key=lambda x: x[1]) best_set_idx, best_set_score, best_set_corners = best_set sorted_corners = sorted(best_set_corners, key=lambda name: state.corner_scores[name], reverse=True) recommendations = [] recommendations.append(f"Non-Overlapping Corner Strategy (Set {best_set_idx + 1} with Total Score: {best_set_score})") recommendations.append("Hottest Non-Overlapping Corners (Sorted by Hotness):") for i, name in enumerate(sorted_corners, 1): score = state.corner_scores[name] recommendations.append(f"{i}. {name}: {score}") return "\n".join(recommendations) def romanowksy_missing_dozen_strategy(): recommendations = [] sorted_dozens = sorted(state.dozen_scores.items(), key=lambda x: x[1], reverse=True) dozens_hits = [item for item in sorted_dozens if item[1] > 0] dozens_no_hits = [item for item in sorted_dozens if item[1] == 0] if not dozens_hits and not dozens_no_hits: recommendations.append("Romanowksy Missing Dozen Strategy: No spins recorded yet.") return "\n".join(recommendations) if len(dozens_hits) < 2: recommendations.append("Romanowksy Missing Dozen Strategy: Not enough dozens have hit yet.") if dozens_hits: recommendations.append(f"Hottest Dozen: {dozens_hits[0][0]} (Score: {dozens_hits[0][1]})") return "\n".join(recommendations) top_dozens = [] scores_seen = set() for name, score in sorted_dozens: if len(top_dozens) < 2 or score in scores_seen: top_dozens.append((name, score)) scores_seen.add(score) else: break recommendations.append("Hottest Dozens (Top 2):") for i, (name, score) in enumerate(top_dozens[:2], 1): recommendations.append(f"{i}. {name}: {score}") if len(top_dozens) > 2 and top_dozens[1][1] == top_dozens[2][1]: tied_dozens = [name for name, score in top_dozens if score == top_dozens[1][1]] recommendations.append(f"Note: Tie detected among {', '.join(tied_dozens)} with score {top_dozens[1][1]}") weakest_dozen = sorted_dozens[-1] weakest_dozen_name, weakest_dozen_score = weakest_dozen recommendations.append(f"\nWeakest Dozen: {weakest_dozen_name} (Score: {weakest_dozen_score})") weakest_dozen_numbers = set(DOZENS[weakest_dozen_name]) straight_up_df = pd.DataFrame(list(state.scores.items()), columns=["Number", "Score"]) straight_up_df = straight_up_df[straight_up_df["Score"] > 0].sort_values(by="Score", ascending=False) if straight_up_df.empty: recommendations.append("No strong numbers have hit yet in any dozen.") return "\n".join(recommendations) strong_numbers_in_weakest = [] neighbors_in_weakest = [] for _, row in straight_up_df.iterrows(): number = row["Number"] score = row["Score"] if number in weakest_dozen_numbers: strong_numbers_in_weakest.append((number, score)) else: if number in current_neighbors: left, right = current_neighbors[number] if left in weakest_dozen_numbers: neighbors_in_weakest.append((left, number, score)) if right in weakest_dozen_numbers: neighbors_in_weakest.append((right, number, score)) if strong_numbers_in_weakest: recommendations.append("\nStrongest Numbers in Weakest Dozen:") for number, score in strong_numbers_in_weakest: recommendations.append(f"Number {number} (Score: {score})") else: recommendations.append("\nNo strong numbers directly in the Weakest Dozen.") if neighbors_in_weakest: recommendations.append("\nNeighbors of Strong Numbers in Weakest Dozen:") for neighbor, strong_number, score in neighbors_in_weakest: recommendations.append(f"Number {neighbor} (Neighbor of {strong_number}, Score: {score})") else: if not strong_numbers_in_weakest: recommendations.append("No neighbors of strong numbers in the Weakest Dozen.") return "\n".join(recommendations) def fibonacci_to_fortune_strategy(): recommendations = [] # Debug: Print scores to verify state print(f"fibonacci_to_fortune_strategy: Dozen scores = {dict(state.dozen_scores)}") print(f"fibonacci_to_fortune_strategy: Column scores = {dict(state.column_scores)}") print(f"fibonacci_to_fortune_strategy: Even money scores = {dict(state.even_money_scores)}") # Part 1: Fibonacci Strategy (Best Category: Dozens or Columns) sorted_dozens = sorted(state.dozen_scores.items(), key=lambda x: x[1], reverse=True) dozens_hits = [item for item in sorted_dozens if item[1] > 0] sorted_columns = sorted(state.column_scores.items(), key=lambda x: x[1], reverse=True) columns_hits = [item for item in sorted_columns if item[1] > 0] best_dozen_score = dozens_hits[0][1] if dozens_hits else 0 best_column_score = columns_hits[0][1] if columns_hits else 0 recommendations.append("Fibonacci Strategy:") if not dozens_hits and not columns_hits: recommendations.append("No hits in Dozens or Columns yet.") elif best_dozen_score > best_column_score: recommendations.append(f"Best Category: Dozens (Score: {best_dozen_score})") recommendations.append(f"Best Dozen: {dozens_hits[0][0]}") elif best_column_score > best_dozen_score: recommendations.append(f"Best Category: Columns (Score: {best_column_score})") recommendations.append(f"Best Column: {columns_hits[0][0]}") else: recommendations.append(f"Best Category (Tied): Dozens and Columns (Score: {best_dozen_score})") if dozens_hits: recommendations.append(f"Best Dozen: {dozens_hits[0][0]}") if columns_hits: recommendations.append(f"Best Column: {columns_hits[0][0]}") # Part 2: Dozens (Top 2) recommendations.append("\nDozens (Top 2):") print(f"fibonacci_to_fortune_strategy: Sorted dozens = {sorted_dozens}") if len(sorted_dozens) >= 2: for i, (name, score) in enumerate(sorted_dozens[:2], 1): recommendations.append(f"{i}. {name}: {score}") elif sorted_dozens: name, score = sorted_dozens[0] recommendations.append(f"1. {name}: {score}") recommendations.append("2. No other dozens available.") else: recommendations.append("No hits yet.") # Part 3: Columns (Top 2) recommendations.append("\nColumns (Top 2):") print(f"fibonacci_to_fortune_strategy: Sorted columns = {sorted_columns}") if len(sorted_columns) >= 2: for i, (name, score) in enumerate(sorted_columns[:2], 1): recommendations.append(f"{i}. {name}: {score}") elif sorted_columns: name, score = sorted_columns[0] recommendations.append(f"1. {name}: {score}") recommendations.append("2. No other columns available.") else: recommendations.append("No hits yet.") # Part 4: Best Even Money Bet sorted_even_money = sorted(state.even_money_scores.items(), key=lambda x: x[1], reverse=True) print(f"fibonacci_to_fortune_strategy: Sorted even money = {sorted_even_money}") even_money_hits = [item for item in sorted_even_money if item[1] > 0] recommendations.append("\nEven Money (Top 1):") if even_money_hits: best_even_money = even_money_hits[0] name, score = best_even_money recommendations.append(f"1. {name}: {score}") else: recommendations.append("No hits yet.") # Part 5: Best Double Street in Weakest Dozen (Excluding Top Two Dozens) weakest_dozen = min(state.dozen_scores.items(), key=lambda x: x[1], default=("1st Dozen", 0)) weakest_dozen_name, weakest_dozen_score = weakest_dozen weakest_dozen_numbers = set(DOZENS[weakest_dozen_name]) top_two_dozens = [item[0] for item in sorted_dozens[:2]] top_two_dozen_numbers = set() for dozen_name in top_two_dozens: top_two_dozen_numbers.update(DOZENS[dozen_name]) double_streets_in_weakest = [] for name, numbers in SIX_LINES.items(): numbers_set = set(numbers) if numbers_set.issubset(weakest_dozen_numbers) and not numbers_set.intersection(top_two_dozen_numbers): score = state.six_line_scores.get(name, 0) double_streets_in_weakest.append((name, score)) print(f"fibonacci_to_fortune_strategy: Double streets in weakest dozen ({weakest_dozen_name}) = {double_streets_in_weakest}") recommendations.append(f"\nDouble Streets (Top 1 in Weakest Dozen: {weakest_dozen_name}, Score: {weakest_dozen_score}):") if double_streets_in_weakest: double_streets_sorted = sorted(double_streets_in_weakest, key=lambda x: x[1], reverse=True) best_double_street = double_streets_sorted[0] name, score = best_double_street numbers = ', '.join(map(str, sorted(SIX_LINES[name]))) recommendations.append(f"1. {name} (Numbers: {numbers}, Score: {score})") else: recommendations.append("No suitable double street available (all overlap with top two dozens or no hits).") return "\n".join(recommendations) def three_eight_six_rising_martingale(): recommendations = [] sorted_streets = sorted(state.street_scores.items(), key=lambda x: x[1], reverse=True) streets_hits = [item for item in sorted_streets if item[1] > 0] if not streets_hits: recommendations.append("3-8-6 Rising Martingale: No streets have hit yet.") return "\n".join(recommendations) recommendations.append("Top 3 Streets (Yellow):") for i, (name, score) in enumerate(streets_hits[:3], 1): recommendations.append(f"{i}. {name}: {score}") recommendations.append("\nMiddle 3 Streets (Cyan):") for i, (name, score) in enumerate(streets_hits[3:6], 1): recommendations.append(f"{i}. {name}: {score}") recommendations.append("\nBottom 2 Streets (Green):") for i, (name, score) in enumerate(streets_hits[6:8], 1): recommendations.append(f"{i}. {name}: {score}") return "\n".join(recommendations) def one_dozen_one_column_strategy(): recommendations = [] sorted_dozens = sorted(state.dozen_scores.items(), key=lambda x: x[1], reverse=True) dozens_hits = [item for item in sorted_dozens if item[1] > 0] if not dozens_hits: recommendations.append("Best Dozen: No dozens have hit yet.") else: top_score = dozens_hits[0][1] top_dozens = [item for item in sorted_dozens if item[1] == top_score] if len(top_dozens) == 1: recommendations.append(f"Best Dozen: {top_dozens[0][0]}") else: recommendations.append("Best Dozens (Tied):") for name, _ in top_dozens: recommendations.append(f"- {name}") sorted_columns = sorted(state.column_scores.items(), key=lambda x: x[1], reverse=True) columns_hits = [item for item in sorted_columns if item[1] > 0] if not columns_hits: recommendations.append("Best Column: No columns have hit yet.") else: top_score = columns_hits[0][1] top_columns = [item for item in sorted_columns if item[1] == top_score] if len(top_columns) == 1: recommendations.append(f"Best Column: {top_columns[0][0]}") else: recommendations.append("Best Columns (Tied):") for name, _ in top_columns: recommendations.append(f"- {name}") return "\n".join(recommendations) def top_pick_18_numbers_without_neighbours(): recommendations = [] straight_up_df = pd.DataFrame(list(state.scores.items()), columns=["Number", "Score"]) straight_up_df = straight_up_df[straight_up_df["Score"] > 0].sort_values(by="Score", ascending=False) if straight_up_df.empty or len(straight_up_df) < 18: recommendations.append("Top Pick 18 Numbers without Neighbours: Not enough numbers have hit yet (need at least 18).") return "\n".join(recommendations) top_18_df = straight_up_df.head(18) top_18_numbers = top_18_df["Number"].tolist() top_6 = top_18_numbers[:6] next_6 = top_18_numbers[6:12] last_6 = top_18_numbers[12:18] recommendations.append("Top Pick 18 Numbers without Neighbours:") recommendations.append("\nTop 6 Numbers (Yellow):") for i, num in enumerate(top_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nNext 6 Numbers (Blue):") for i, num in enumerate(next_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nLast 6 Numbers (Green):") for i, num in enumerate(last_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") return "\n".join(recommendations) def best_even_money_and_top_18(): recommendations = [] # Best Even Money Bets (Top 3 with tie handling, same as best_even_money_bets) sorted_even_money = sorted(state.even_money_scores.items(), key=lambda x: x[1], reverse=True) even_money_hits = [item for item in sorted_even_money if item[1] > 0] if even_money_hits: # Collect the top 3 bets, including ties top_bets = [] scores_seen = set() for name, score in sorted_even_money: if len(top_bets) < 3 or score in scores_seen: top_bets.append((name, score)) scores_seen.add(score) else: break # Display the top 3 bets recommendations.append("Best Even Money Bets (Top 3):") for i, (name, score) in enumerate(top_bets[:3], 1): recommendations.append(f"{i}. {name}: {score}") # Check for ties among the top 3 positions if len(top_bets) > 1: first_score = top_bets[0][1] tied_first = [name for name, score in top_bets if score == first_score] if len(tied_first) > 1: recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_first)} with score {first_score}") if len(top_bets) > 1: second_score = top_bets[1][1] tied_second = [name for name, score in top_bets if score == second_score] if len(tied_second) > 1: recommendations.append(f"Note: Tie for 2nd place among {', '.join(tied_second)} with score {second_score}") if len(top_bets) > 2: third_score = top_bets[2][1] tied_third = [name for name, score in top_bets if score == third_score] if len(tied_third) > 1: recommendations.append(f"Note: Tie for 3rd place among {', '.join(tied_third)} with score {third_score}") else: recommendations.append("Best Even Money Bets: No hits yet.") # Top Pick 18 Numbers without Neighbours (same as top_pick_18_numbers_without_neighbours) recommendations.append("") # Add a blank line for separation straight_up_df = pd.DataFrame(list(state.scores.items()), columns=["Number", "Score"]) straight_up_df = straight_up_df[straight_up_df["Score"] > 0].sort_values(by="Score", ascending=False) if straight_up_df.empty or len(straight_up_df) < 18: recommendations.append("Top Pick 18 Numbers without Neighbours: Not enough numbers have hit yet (need at least 18).") return "\n".join(recommendations) top_18_df = straight_up_df.head(18) top_18_numbers = top_18_df["Number"].tolist() top_6 = top_18_numbers[:6] next_6 = top_18_numbers[6:12] last_6 = top_18_numbers[12:18] recommendations.append("Top Pick 18 Numbers without Neighbours:") recommendations.append("\nTop 6 Numbers (Yellow):") for i, num in enumerate(top_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nNext 6 Numbers (Blue):") for i, num in enumerate(next_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nLast 6 Numbers (Green):") for i, num in enumerate(last_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") return "\n".join(recommendations) def best_dozens_and_top_18(): recommendations = [] # Best Dozens (Top 2 with tie handling, same as best_dozens) sorted_dozens = sorted(state.dozen_scores.items(), key=lambda x: x[1], reverse=True) dozens_hits = [item for item in sorted_dozens if item[1] > 0] if dozens_hits: # Collect the top 2 dozens, including ties top_dozens = [] scores_seen = set() for name, score in sorted_dozens: if len(top_dozens) < 2 or score in scores_seen: top_dozens.append((name, score)) scores_seen.add(score) else: break # Display the top 2 dozens recommendations.append("Best Dozens (Top 2):") for i, (name, score) in enumerate(top_dozens[:2], 1): recommendations.append(f"{i}. {name}: {score}") # Check for ties among the top 2 positions if len(top_dozens) > 1: first_score = top_dozens[0][1] tied_first = [name for name, score in top_dozens if score == first_score] if len(tied_first) > 1: recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_first)} with score {first_score}") if len(top_dozens) > 1: second_score = top_dozens[1][1] tied_second = [name for name, score in top_dozens if score == second_score] if len(tied_second) > 1: recommendations.append(f"Note: Tie for 2nd place among {', '.join(tied_second)} with score {second_score}") else: recommendations.append("Best Dozens: No hits yet.") # Top Pick 18 Numbers without Neighbours (same as top_pick_18_numbers_without_neighbours) recommendations.append("") # Add a blank line for separation straight_up_df = pd.DataFrame(list(state.scores.items()), columns=["Number", "Score"]) straight_up_df = straight_up_df[straight_up_df["Score"] > 0].sort_values(by="Score", ascending=False) if straight_up_df.empty or len(straight_up_df) < 18: recommendations.append("Top Pick 18 Numbers without Neighbours: Not enough numbers have hit yet (need at least 18).") return "\n".join(recommendations) top_18_df = straight_up_df.head(18) top_18_numbers = top_18_df["Number"].tolist() top_6 = top_18_numbers[:6] next_6 = top_18_numbers[6:12] last_6 = top_18_numbers[12:18] recommendations.append("Top Pick 18 Numbers without Neighbours:") recommendations.append("\nTop 6 Numbers (Yellow):") for i, num in enumerate(top_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nNext 6 Numbers (Blue):") for i, num in enumerate(next_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nLast 6 Numbers (Green):") for i, num in enumerate(last_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") return "\n".join(recommendations) def best_columns_and_top_18(): recommendations = [] # Best Columns (Top 2 with tie handling, same as best_columns) sorted_columns = sorted(state.column_scores.items(), key=lambda x: x[1], reverse=True) columns_hits = [item for item in sorted_columns if item[1] > 0] if columns_hits: # Collect the top 2 columns, including ties top_columns = [] scores_seen = set() for name, score in sorted_columns: if len(top_columns) < 2 or score in scores_seen: top_columns.append((name, score)) scores_seen.add(score) else: break # Display the top 2 columns recommendations.append("Best Columns (Top 2):") for i, (name, score) in enumerate(top_columns[:2], 1): recommendations.append(f"{i}. {name}: {score}") # Check for ties among the top 2 positions if len(top_columns) > 1: first_score = top_columns[0][1] tied_first = [name for name, score in top_columns if score == first_score] if len(tied_first) > 1: recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_first)} with score {first_score}") if len(top_columns) > 1: second_score = top_columns[1][1] tied_second = [name for name, score in top_columns if score == second_score] if len(tied_second) > 1: recommendations.append(f"Note: Tie for 2nd place among {', '.join(tied_second)} with score {second_score}") else: recommendations.append("Best Columns: No hits yet.") # Top Pick 18 Numbers without Neighbours (same as top_pick_18_numbers_without_neighbours) recommendations.append("") # Add a blank line for separation straight_up_df = pd.DataFrame(list(state.scores.items()), columns=["Number", "Score"]) straight_up_df = straight_up_df[straight_up_df["Score"] > 0].sort_values(by="Score", ascending=False) if straight_up_df.empty or len(straight_up_df) < 18: recommendations.append("Top Pick 18 Numbers without Neighbours: Not enough numbers have hit yet (need at least 18).") return "\n".join(recommendations) top_18_df = straight_up_df.head(18) top_18_numbers = top_18_df["Number"].tolist() top_6 = top_18_numbers[:6] next_6 = top_18_numbers[6:12] last_6 = top_18_numbers[12:18] recommendations.append("Top Pick 18 Numbers without Neighbours:") recommendations.append("\nTop 6 Numbers (Yellow):") for i, num in enumerate(top_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nNext 6 Numbers (Blue):") for i, num in enumerate(next_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nLast 6 Numbers (Green):") for i, num in enumerate(last_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") return "\n".join(recommendations) def best_dozens_even_money_and_top_18(): recommendations = [] # Best Dozens (Top 2 with tie handling, same as best_dozens) sorted_dozens = sorted(state.dozen_scores.items(), key=lambda x: x[1], reverse=True) dozens_hits = [item for item in sorted_dozens if item[1] > 0] if dozens_hits: # Collect the top 2 dozens, including ties top_dozens = [] scores_seen = set() for name, score in sorted_dozens: if len(top_dozens) < 2 or score in scores_seen: top_dozens.append((name, score)) scores_seen.add(score) else: break # Display the top 2 dozens recommendations.append("Best Dozens (Top 2):") for i, (name, score) in enumerate(top_dozens[:2], 1): recommendations.append(f"{i}. {name}: {score}") # Check for ties among the top 2 positions if len(top_dozens) > 1: first_score = top_dozens[0][1] tied_first = [name for name, score in top_dozens if score == first_score] if len(tied_first) > 1: recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_first)} with score {first_score}") if len(top_dozens) > 1: second_score = top_dozens[1][1] tied_second = [name for name, score in top_dozens if score == second_score] if len(tied_second) > 1: recommendations.append(f"Note: Tie for 2nd place among {', '.join(tied_second)} with score {second_score}") else: recommendations.append("Best Dozens: No hits yet.") # Best Even Money Bets (Top 3 with tie handling, same as best_even_money_bets) recommendations.append("") # Add a blank line for separation sorted_even_money = sorted(state.even_money_scores.items(), key=lambda x: x[1], reverse=True) even_money_hits = [item for item in sorted_even_money if item[1] > 0] if even_money_hits: # Collect the top 3 bets, including ties top_bets = [] scores_seen = set() for name, score in sorted_even_money: if len(top_bets) < 3 or score in scores_seen: top_bets.append((name, score)) scores_seen.add(score) else: break # Display the top 3 bets recommendations.append("Best Even Money Bets (Top 3):") for i, (name, score) in enumerate(top_bets[:3], 1): recommendations.append(f"{i}. {name}: {score}") # Check for ties among the top 3 positions if len(top_bets) > 1: first_score = top_bets[0][1] tied_first = [name for name, score in top_bets if score == first_score] if len(tied_first) > 1: recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_first)} with score {first_score}") if len(top_bets) > 1: second_score = top_bets[1][1] tied_second = [name for name, score in top_bets if score == second_score] if len(tied_second) > 1: recommendations.append(f"Note: Tie for 2nd place among {', '.join(tied_second)} with score {second_score}") if len(top_bets) > 2: third_score = top_bets[2][1] tied_third = [name for name, score in top_bets if score == third_score] if len(tied_third) > 1: recommendations.append(f"Note: Tie for 3rd place among {', '.join(tied_third)} with score {third_score}") else: recommendations.append("Best Even Money Bets: No hits yet.") # Top Pick 18 Numbers without Neighbours (same as top_pick_18_numbers_without_neighbours) recommendations.append("") # Add a blank line for separation straight_up_df = pd.DataFrame(list(state.scores.items()), columns=["Number", "Score"]) straight_up_df = straight_up_df[straight_up_df["Score"] > 0].sort_values(by="Score", ascending=False) if straight_up_df.empty or len(straight_up_df) < 18: recommendations.append("Top Pick 18 Numbers without Neighbours: Not enough numbers have hit yet (need at least 18).") return "\n".join(recommendations) top_18_df = straight_up_df.head(18) top_18_numbers = top_18_df["Number"].tolist() top_6 = top_18_numbers[:6] next_6 = top_18_numbers[6:12] last_6 = top_18_numbers[12:18] recommendations.append("Top Pick 18 Numbers without Neighbours:") recommendations.append("\nTop 6 Numbers (Yellow):") for i, num in enumerate(top_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nNext 6 Numbers (Blue):") for i, num in enumerate(next_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nLast 6 Numbers (Green):") for i, num in enumerate(last_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") return "\n".join(recommendations) def best_columns_even_money_and_top_18(): recommendations = [] # Best Columns (Top 2 with tie handling, same as best_columns) sorted_columns = sorted(state.column_scores.items(), key=lambda x: x[1], reverse=True) columns_hits = [item for item in sorted_columns if item[1] > 0] if columns_hits: # Collect the top 2 columns, including ties top_columns = [] scores_seen = set() for name, score in sorted_columns: if len(top_columns) < 2 or score in scores_seen: top_columns.append((name, score)) scores_seen.add(score) else: break # Display the top 2 columns recommendations.append("Best Columns (Top 2):") for i, (name, score) in enumerate(top_columns[:2], 1): recommendations.append(f"{i}. {name}: {score}") # Check for ties among the top 2 positions if len(top_columns) > 1: first_score = top_columns[0][1] tied_first = [name for name, score in top_columns if score == first_score] if len(tied_first) > 1: recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_first)} with score {first_score}") if len(top_columns) > 1: second_score = top_columns[1][1] tied_second = [name for name, score in top_columns if score == second_score] if len(tied_second) > 1: recommendations.append(f"Note: Tie for 2nd place among {', '.join(tied_second)} with score {second_score}") else: recommendations.append("Best Columns: No hits yet.") # Best Even Money Bets (Top 3 with tie handling, same as best_even_money_bets) recommendations.append("") # Add a blank line for separation sorted_even_money = sorted(state.even_money_scores.items(), key=lambda x: x[1], reverse=True) even_money_hits = [item for item in sorted_even_money if item[1] > 0] if even_money_hits: # Collect the top 3 bets, including ties top_bets = [] scores_seen = set() for name, score in sorted_even_money: if len(top_bets) < 3 or score in scores_seen: top_bets.append((name, score)) scores_seen.add(score) else: break # Display the top 3 bets recommendations.append("Best Even Money Bets (Top 3):") for i, (name, score) in enumerate(top_bets[:3], 1): recommendations.append(f"{i}. {name}: {score}") # Check for ties among the top 3 positions if len(top_bets) > 1: first_score = top_bets[0][1] tied_first = [name for name, score in top_bets if score == first_score] if len(tied_first) > 1: recommendations.append(f"Note: Tie for 1st place among {', '.join(tied_first)} with score {first_score}") if len(top_bets) > 1: second_score = top_bets[1][1] tied_second = [name for name, score in top_bets if score == second_score] if len(tied_second) > 1: recommendations.append(f"Note: Tie for 2nd place among {', '.join(tied_second)} with score {second_score}") if len(top_bets) > 2: third_score = top_bets[2][1] tied_third = [name for name, score in top_bets if score == third_score] if len(tied_third) > 1: recommendations.append(f"Note: Tie for 3rd place among {', '.join(tied_third)} with score {third_score}") else: recommendations.append("Best Even Money Bets: No hits yet.") # Top Pick 18 Numbers without Neighbours (same as top_pick_18_numbers_without_neighbours) recommendations.append("") # Add a blank line for separation straight_up_df = pd.DataFrame(list(state.scores.items()), columns=["Number", "Score"]) straight_up_df = straight_up_df[straight_up_df["Score"] > 0].sort_values(by="Score", ascending=False) if straight_up_df.empty or len(straight_up_df) < 18: recommendations.append("Top Pick 18 Numbers without Neighbours: Not enough numbers have hit yet (need at least 18).") return "\n".join(recommendations) top_18_df = straight_up_df.head(18) top_18_numbers = top_18_df["Number"].tolist() top_6 = top_18_numbers[:6] next_6 = top_18_numbers[6:12] last_6 = top_18_numbers[12:18] recommendations.append("Top Pick 18 Numbers without Neighbours:") recommendations.append("\nTop 6 Numbers (Yellow):") for i, num in enumerate(top_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nNext 6 Numbers (Blue):") for i, num in enumerate(next_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") recommendations.append("\nLast 6 Numbers (Green):") for i, num in enumerate(last_6, 1): score = top_18_df[top_18_df["Number"] == num]["Score"].iloc[0] recommendations.append(f"{i}. Number {num} (Score: {score})") return "\n".join(recommendations) def create_color_code_table(): html = '''| Color | Meaning |
|---|---|
| Yellow (Top Tier) | Indicates the hottest or top-ranked numbers/sections (e.g., top 3 or top 6 in most strategies). For Dozen Tracker, this highlights the most frequent Dozen when no strategy is selected. Can be changed via color pickers. |
| Cyan (Middle Tier) | Represents the second tier of trending numbers/sections (e.g., ranks 4-6 or secondary picks). For Dozen Tracker, this highlights the second most frequent Dozen when no strategy is selected. Can be changed via color pickers. |
| Green (Lower Tier) | Marks the third tier of strong numbers/sections (e.g., ranks 7-9 or lower priority). Can be changed via color pickers. |
| Light Gray (Cold Top) | Used in Cold Bet Strategy for the coldest top-tier sections (least hits). Fixed for this strategy. |
| Plum (Cold Middle) | Used in Cold Bet Strategy for middle-tier cold sections. Fixed for this strategy. |
| Light Cyan (Cold Lower) | Used in Cold Bet Strategy for lower-tier cold sections. Fixed for this strategy. |
| Red | Default color for red numbers on the roulette table. |
| Black | Default color for black numbers on the roulette table. |
| Green | Default color for zero (0) on the roulette table. |
| Tomato Red | Used in Dozen Tracker to represent the 1st Dozen. |
| Steel Blue | Used in Dozen Tracker to represent the 2nd Dozen. |
| Lime Green | Used in Dozen Tracker to represent the 3rd Dozen. |
| Gray | Used in Dozen Tracker to represent spins not in any Dozen (i.e., 0). |
Top Numbers with Neighbours (Tiered): No numbers have hit yet.
" # Start with the HTML table for Strongest Numbers table_html = '| Hit | Left N. | Right N. |
|---|---|---|
| {num} | {left} | {right} |
Top Tier (Yellow):
") for i, num in enumerate(top_8, 1): score = number_scores.get(num, "Neighbor") recommendations.append(f"{i}. Number {num} (Score: {score})
") recommendations.append("Second Tier (Blue):
") for i, num in enumerate(next_8, 1): score = number_scores.get(num, "Neighbor") recommendations.append(f"{i}. Number {num} (Score: {score})
") recommendations.append("Third Tier (Green):
") for i, num in enumerate(last_8, 1): score = number_scores.get(num, "Neighbor") recommendations.append(f"{i}. Number {num} (Score: {score})
") return "\n".join(recommendations) # Line 1: Start of neighbours_of_strong_number function (updated) def neighbours_of_strong_number(neighbours_count, strong_numbers_count): """Recommend numbers and their neighbors based on hit frequency, including strategy recommendations with tie information.""" recommendations = [] # Validate inputs try: neighbours_count = int(neighbours_count) strong_numbers_count = int(strong_numbers_count) if neighbours_count < 0 or strong_numbers_count < 0: raise ValueError("Neighbours count and strong numbers count must be non-negative.") if strong_numbers_count == 0: raise ValueError("Strong numbers count must be at least 1.") except (ValueError, TypeError) as e: return f"Error: Invalid input - {str(e)}. Please use positive integers for neighbours and strong numbers.", {} # Check if current_neighbors is valid if not isinstance(current_neighbors, dict): return "Error: Neighbor data is not properly configured. Contact support.", {} for key, value in current_neighbors.items(): if not isinstance(key, int) or not isinstance(value, tuple) or len(value) != 2: return "Error: Neighbor data is malformed. Contact support.", {} try: print(f"neighbours_of_strong_number: Starting with neighbours_count = {neighbours_count}, strong_numbers_count = {strong_numbers_count}") sorted_numbers = sorted(state.scores.items(), key=lambda x: (-x[1], x[0])) numbers_hits = [item for item in sorted_numbers if item[1] > 0] if not numbers_hits: recommendations.append("Neighbours of Strong Number: No numbers have hit yet.") return "\n".join(recommendations), {} # Limit strong_numbers_count to available hits strong_numbers_count = min(strong_numbers_count, len(numbers_hits)) top_numbers = [item[0] for item in numbers_hits[:strong_numbers_count]] top_scores = {item[0]: item[1] for item in numbers_hits[:strong_numbers_count]} selected_numbers = set(top_numbers) neighbors_set = set() # Calculate neighbors for each strong number for strong_number in top_numbers: if strong_number not in current_neighbors: recommendations.append(f"Warning: No neighbor data for number {strong_number}. Skipping its neighbors.") continue current_number = strong_number # Left neighbors for i in range(neighbours_count): left, _ = current_neighbors.get(current_number, (None, None)) if left is not None: neighbors_set.add(left) current_number = left else: break # Right neighbors current_number = strong_number for i in range(neighbours_count): _, right = current_neighbors.get(current_number, (None, None)) if right is not None: neighbors_set.add(right) current_number = right else: break # Remove overlap (strong numbers take precedence) neighbors_set = neighbors_set - selected_numbers print(f"neighbours_of_strong_number: Strong numbers = {sorted(list(selected_numbers))}") print(f"neighbours_of_strong_number: Neighbors = {sorted(list(neighbors_set))}") # Combine all bet numbers (strong numbers + neighbors) for aggregated scoring bet_numbers = list(selected_numbers) + list(neighbors_set) # Calculate Aggregated Scores for the bet numbers (needed for Suggestions) even_money_scores, dozen_scores, column_scores = state.calculate_aggregated_scores_for_spins(bet_numbers) # Determine the best even money bet and check for ties sorted_even_money = sorted(even_money_scores.items(), key=lambda x: (-x[1], x[0])) best_even_money = sorted_even_money[0] if sorted_even_money else ("None", 0) best_even_money_name, best_even_money_hits = best_even_money # Check for ties in even money bets even_money_ties = [] if sorted_even_money and best_even_money_hits > 0: even_money_ties = [f"{name}: {score}" for name, score in sorted_even_money if score == best_even_money_hits and name != best_even_money_name] even_money_tie_text = f" (Tied with {', '.join(even_money_ties)})" if even_money_ties else "" # Determine the best dozen and best column best_dozen = max(dozen_scores.items(), key=lambda x: x[1], default=("None", 0)) best_dozen_name, best_dozen_hits = best_dozen best_column = max(column_scores.items(), key=lambda x: x[1], default=("None", 0)) best_column_name, best_column_hits = best_column # Compare dozens vs. columns for the stronger section and check for ties suggestion = "" winner_category = "" best_bet_tie_text = "" if best_dozen_hits > best_column_hits: suggestion = f"{best_dozen_name}: {best_dozen_hits}" winner_category = "dozen" # Check if the best dozen ties with others sorted_dozens = sorted(dozen_scores.items(), key=lambda x: (-x[1], x[0])) dozen_ties = [f"{name}: {score}" for name, score in sorted_dozens if score == best_dozen_hits and name != best_dozen_name] if dozen_ties: best_bet_tie_text = f" (Tied with {', '.join(dozen_ties)})" elif best_column_hits > best_dozen_hits: suggestion = f"{best_column_name}: {best_column_hits}" winner_category = "column" # Check if the best column ties with others sorted_columns = sorted(column_scores.items(), key=lambda x: (-x[1], x[0])) column_ties = [f"{name}: {score}" for name, score in sorted_columns if score == best_column_hits and name != best_column_name] if column_ties: best_bet_tie_text = f" (Tied with {', '.join(column_ties)})" else: # Check for ties between dozens and columns at the top level sorted_dozens = sorted(dozen_scores.items(), key=lambda x: (-x[1], x[0])) sorted_columns = sorted(column_scores.items(), key=lambda x: (-x[1], x[0])) if len(sorted_dozens) >= 2 and sorted_dozens[0][1] == sorted_dozens[1][1] and sorted_dozens[0][1] > 0: # Two dozens tie at the highest hit count suggestion = f"{sorted_dozens[0][0]} and {sorted_dozens[1][0]}: {sorted_dozens[0][1]}" winner_category = "dozen" # Check for additional dozen ties dozen_ties = [f"{name}: {score}" for name, score in sorted_dozens[2:] if score == sorted_dozens[0][1]] if dozen_ties: best_bet_tie_text = f" (Tied with {', '.join(dozen_ties)})" elif len(sorted_columns) >= 2 and sorted_columns[0][1] == sorted_columns[1][1] and sorted_columns[0][1] > 0: # Two columns tie at the highest hit count suggestion = f"{sorted_columns[0][0]} and {sorted_columns[1][0]}: {sorted_columns[0][1]}" winner_category = "column" # Check for additional column ties column_ties = [f"{name}: {score}" for name, score in sorted_columns[2:] if score == sorted_columns[0][1]] if column_ties: best_bet_tie_text = f" (Tied with {', '.join(column_ties)})" else: # Default to the best dozen (alphabetically if tied), check for ties with columns suggestion = f"{best_dozen_name}: {best_dozen_hits}" winner_category = "dozen" if best_dozen_hits == best_column_hits and best_column_hits > 0: best_bet_tie_text = f" (Tied with {best_column_name}: {best_column_hits})" # Determine the top two winners in the winning category (dozens or columns) and check for ties two_winners_suggestion = "" two_winners_tie_text = "" if winner_category == "dozen": sorted_dozens = sorted(dozen_scores.items(), key=lambda x: (-x[1], x[0])) top_two_dozens = sorted_dozens[:2] # Take top two dozens if top_two_dozens[0][1] > 0: # Only suggest if there are hits two_winners_suggestion = f"Play Two Dozens: {top_two_dozens[0][0]} ({top_two_dozens[0][1]}) and {top_two_dozens[1][0]} ({top_two_dozens[1][1]})" # Check if the second dozen ties with others if len(sorted_dozens) > 2: second_score = top_two_dozens[1][1] ties = [f"{name}: {score}" for name, score in sorted_dozens[2:] if score == second_score] if ties: two_winners_tie_text = f" (Tied with {', '.join(ties)})" else: two_winners_suggestion = "Play Two Dozens: Not enough hits to suggest two dozens." elif winner_category == "column": sorted_columns = sorted(column_scores.items(), key=lambda x: (-x[1], x[0])) top_two_columns = sorted_columns[:2] # Take top two columns if top_two_columns[0][1] > 0: # Only suggest if there are hits two_winners_suggestion = f"Play Two Columns: {top_two_columns[0][0]} ({top_two_columns[0][1]}) and {top_two_columns[1][0]} ({top_two_columns[1][1]})" # Check if the second column ties with others if len(sorted_columns) > 2: second_score = top_two_columns[1][1] ties = [f"{name}: {score}" for name, score in sorted_columns[2:] if score == second_score] if ties: two_winners_tie_text = f" (Tied with {', '.join(ties)})" else: two_winners_suggestion = "Play Two Columns: Not enough hits to suggest two columns." # Create the suggestions dictionary suggestions = { "best_even_money": f"{best_even_money_name}: {best_even_money_hits}{even_money_tie_text}", "best_bet": f"{suggestion}{best_bet_tie_text}", "play_two": f"{two_winners_suggestion}{two_winners_tie_text}" } # Append the Suggestions section first recommendations.append("Suggestions:") recommendations.append(f"Best Even Money Bet: {best_even_money_name}: {best_even_money_hits}{even_money_tie_text}") recommendations.append(f"Best Bet: {suggestion}{best_bet_tie_text}") recommendations.append(f"{two_winners_suggestion}{two_winners_tie_text}") # Now append the Strongest Numbers and Neighbours section recommendations.append(f"\nTop {strong_numbers_count} Strongest Numbers and Their Neighbours:") recommendations.append("\nStrongest Numbers (Yellow):") for i, num in enumerate(sorted(top_numbers), 1): score = top_scores[num] recommendations.append(f"{i}. Number {num} (Score: {score})") if neighbors_set: recommendations.append(f"\nNeighbours ({neighbours_count} Left + {neighbours_count} Right, Cyan):") for i, num in enumerate(sorted(list(neighbors_set)), 1): recommendations.append(f"{i}. Number {num}") else: recommendations.append(f"\nNeighbours ({neighbours_count} Left + {neighbours_count} Right, Cyan): None") return "\n".join(recommendations), suggestions except Exception as e: print(f"neighbours_of_strong_number: Unexpected error: {str(e)}") return f"Error in Neighbours of Strong Number: Unexpected issue - {str(e)}. Please try again or contact support.", {} # Line 3: Start of dozen_tracker function (unchanged) def dozen_tracker(num_spins_to_check, consecutive_hits_threshold, alert_enabled, sequence_length, follow_up_spins, sequence_alert_enabled): """Track and display the history of Dozen hits for the last N spins, with optional alerts for consecutive hits and sequence matching.""" recommendations = [] sequence_recommendations = [] # Validate inputs try: num_spins_to_check = int(num_spins_to_check) consecutive_hits_threshold = int(consecutive_hits_threshold) sequence_length = int(sequence_length) follow_up_spins = int(follow_up_spins) if num_spins_to_check < 1: return "Error: Number of spins to check must be at least 1.", "Error: Number of spins to check must be at least 1.
", "Error: Number of spins to check must be at least 1.
" if consecutive_hits_threshold < 1: return "Error: Consecutive hits threshold must be at least 1.", "Error: Consecutive hits threshold must be at least 1.
", "Error: Consecutive hits threshold must be at least 1.
" if sequence_length < 1: return "Error: Sequence length must be at least 1.", "Error: Sequence length must be at least 1.
", "Error: Sequence length must be at least 1.
" if follow_up_spins < 1: return "Error: Follow-up spins must be at least 1.", "Error: Follow-up spins must be at least 1.
", "Error: Follow-up spins must be at least 1.
" except (ValueError, TypeError): return "Error: Invalid inputs. Please use positive integers.", "Error: Invalid inputs. Please use positive integers.
", "Error: Invalid inputs. Please use positive integers.
" # Get the last N spins for sequence matching recent_spins = state.last_spins[-num_spins_to_check:] if len(state.last_spins) >= num_spins_to_check else state.last_spins print(f"dozen_tracker: Tracking {num_spins_to_check} spins for sequence matching, recent_spins length = {len(recent_spins)}") if not recent_spins: return "Dozen Tracker: No spins recorded yet.", "Dozen Tracker: No spins recorded yet.
", "Dozen Tracker: No spins recorded yet.
" # Map each spin to its Dozen for sequence matching dozen_pattern = [] dozen_counts = {"1st Dozen": 0, "2nd Dozen": 0, "3rd Dozen": 0, "Not in Dozen": 0} for spin in recent_spins: spin_value = int(spin) if spin_value == 0: dozen_pattern.append("Not in Dozen") dozen_counts["Not in Dozen"] += 1 else: found = False for name, numbers in DOZENS.items(): if spin_value in numbers: dozen_pattern.append(name) dozen_counts[name] += 1 found = True break if not found: dozen_pattern.append("Not in Dozen") dozen_counts["Not in Dozen"] += 1 # Map the entire spin history to Dozens for sequence matching full_dozen_pattern = [] for spin in state.last_spins: spin_value = int(spin) if spin_value == 0: full_dozen_pattern.append("Not in Dozen") else: found = False for name, numbers in DOZENS.items(): if spin_value in numbers: full_dozen_pattern.append(name) found = True break if not found: full_dozen_pattern.append("Not in Dozen") # Detect consecutive Dozen hits in the LAST 3 spins only (if alert is enabled) if alert_enabled: # Take only the last 3 spins (or fewer if not enough spins) last_three_spins = state.last_spins[-3:] if len(state.last_spins) >= 3 else state.last_spins print(f"dozen_tracker: Checking last 3 spins for consecutive hits, last_three_spins = {last_three_spins}") if len(last_three_spins) < 3: print("dozen_tracker: Not enough spins to check for consecutive hits (need at least 3).") state.last_dozen_alert_index = -1 state.last_alerted_spins = None else: # Map the last 3 spins to their Dozens last_three_dozens = [] for spin in last_three_spins: spin_value = int(spin) if spin_value == 0: last_three_dozens.append("Not in Dozen") else: found = False for name, numbers in DOZENS.items(): if spin_value in numbers: last_three_dozens.append(name) found = True break if not found: last_three_dozens.append("Not in Dozen") print(f"dozen_tracker: Last 3 spins dozens = {last_three_dozens}") # Check if all 3 spins are in the same Dozen and not "Not in Dozen" if (last_three_dozens[0] == last_three_dozens[1] == last_three_dozens[2] and last_three_dozens[0] != "Not in Dozen"): current_dozen = last_three_dozens[0] # Convert last_three_spins to a tuple for comparison (immutable and hashable) current_spins_tuple = tuple(last_three_spins) # Check if this set of spins is different from the last alerted set if state.last_alerted_spins != current_spins_tuple: # Include the spins in the alert spins_str = ", ".join(map(str, last_three_spins)) alert_message = f"Alert: {current_dozen} has hit 3 times consecutively! (Spins: {spins_str})" gr.Warning(alert_message) recommendations.append(alert_message) state.last_dozen_alert_index = len(state.last_spins) - 1 # Update the last alerted index state.last_alerted_spins = current_spins_tuple # Store the spins that triggered this alert else: # If the last 3 spins don't form a streak, reset the alert index and spins state.last_dozen_alert_index = -1 state.last_alerted_spins = None # Detect sequence matches (only if sequence alert is enabled) sequence_matches = [] sequence_follow_ups = [] if sequence_alert_enabled and len(full_dozen_pattern) >= sequence_length: # Take the last X spins to check for a match last_x_spins = full_dozen_pattern[-sequence_length:] if len(full_dozen_pattern) >= sequence_length else full_dozen_pattern print(f"dozen_tracker: Checking last {sequence_length} spins for sequence matching, last_x_spins = {last_x_spins}") if len(last_x_spins) < sequence_length: print(f"dozen_tracker: Not enough spins to check for sequence of length {sequence_length}.") else: # Convert the last X spins to a tuple for comparison last_x_pattern = tuple(last_x_spins) # Collect all sequences of length X within the tracking window (recent_spins) sequences = [] for i in range(len(dozen_pattern) - sequence_length + 1): seq = tuple(dozen_pattern[i:i + sequence_length]) # Only consider sequences that end before the last X spins if i + sequence_length <= len(dozen_pattern) - sequence_length: sequences.append((i, seq)) print(f"dozen_tracker: Found {len(sequences)} sequences of length {sequence_length} in the tracking window") # Check if the last X spins match any previous sequence for start_idx, seq in sequences: if seq == last_x_pattern: # Check if we've already alerted for this exact pattern if seq not in state.alerted_patterns: sequence_matches.append((start_idx, seq)) # Get the next Y spins after the first occurrence follow_up_start = start_idx + sequence_length follow_up_end = follow_up_start + follow_up_spins if follow_up_end <= len(dozen_pattern): follow_up = dozen_pattern[follow_up_start:follow_up_end] sequence_follow_ups.append((start_idx, seq, follow_up)) # Mark this pattern as alerted state.alerted_patterns.add(seq) # If a match is found, provide betting recommendations with spin context if sequence_matches: latest_match = max(sequence_matches, key=lambda x: x[0]) # Latest match by start index latest_start_idx, matched_sequence = latest_match # Find the follow-up spins for the first occurrence of this sequence first_occurrence = min((seq for seq in sequences if seq[1] == matched_sequence), key=lambda x: x[0])[0] follow_up_start = first_occurrence + sequence_length follow_up_end = follow_up_start + follow_up_spins # Adjust indices for the full spin history latest_start_idx_full = len(full_dozen_pattern) - sequence_length # Get the actual spins that triggered the sequence sequence_spins = recent_spins[-sequence_length:] # Last X spins sequence_spins_str = ", ".join(map(str, sequence_spins)) if follow_up_end <= len(dozen_pattern): follow_up = dozen_pattern[follow_up_start:follow_up_end] alert_message = f"Alert: Sequence {', '.join(matched_sequence)} has repeated at spins {sequence_spins_str}!" gr.Warning(alert_message) sequence_recommendations.append(alert_message) sequence_recommendations.append(f"Previous follow-up spins (next {follow_up_spins}): {', '.join(follow_up)}") sequence_recommendations.append("Betting Recommendations (Bet Against Historical Follow-Ups):") all_dozens = ["1st Dozen", "2nd Dozen", "3rd Dozen"] for idx, dozen in enumerate(follow_up): if dozen == "Not in Dozen": sequence_recommendations.append(f"Spin {idx + 1}: 0 (Not in Dozen) - No bet recommendation.") else: dozens_to_bet = [d for d in all_dozens if d != dozen] sequence_recommendations.append(f"Spin {idx + 1}: Bet against {dozen} - Bet on {', '.join(dozens_to_bet)}") else: # If no match is found, reset the alerted patterns to allow future matches state.alerted_patterns.clear() # Text summary for Dozen Tracker recommendations.append(f"Dozen Tracker (Last {len(recent_spins)} Spins):") recommendations.append("Dozen History: " + ", ".join(dozen_pattern)) recommendations.append("\nSummary of Dozen Hits:") for name, count in dozen_counts.items(): recommendations.append(f"{name}: {count} hits") # HTML representation for Dozen Tracker html_output = f'{alert_message}
' html_output += 'Sequence matching is disabled. Enable it to see results.
" elif len(dozen_pattern) < sequence_length: sequence_html_output += f"Not enough spins to match a sequence of length {sequence_length}.
" elif not sequence_matches: sequence_html_output += "No sequence matches found yet.
" else: sequence_html_output += "Error: Inputs must be at least 1.
Even Money Tracker: No spins recorded yet.
Tracking: {tracked_str} ({combination_mode})
' html_output += 'Alert: {tracked_str} hit {max_streak} times consecutively! (Spins: {streak_spins})
' html_output += 'No {number_type.lower()} numbers provided to play.
", update_spin_counter(), render_sides_of_zero_display() ) # Split and clean the input numbers = [num.strip() for num in numbers_input.split(",") if num.strip()] if not numbers: return ( spins_display, spins_display, f"No valid {number_type.lower()} numbers provided.
", update_spin_counter(), render_sides_of_zero_display() ) # Validate numbers (must be integers between 0 and 36) valid_numbers = [] for num in numbers: try: n = int(num) if 0 <= n <= 36: valid_numbers.append(str(n)) else: print(f"Invalid {number_type.lower()} number: {num}. Must be between 0 and 36.") except ValueError: print(f"Invalid {number_type.lower()} number: {num}. Must be an integer.") continue if not valid_numbers: return ( spins_display, spins_display, f"No valid {number_type.lower()} numbers to play. Numbers must be between 0 and 36.
", update_spin_counter(), render_sides_of_zero_display() ) # Update state.last_spins if not hasattr(state, 'last_spins'): state.last_spins = [] # Append the valid numbers to state.last_spins state.last_spins.extend(valid_numbers) # Update spins_display to match state.last_spins new_spins_display = ", ".join(state.last_spins) if state.last_spins else "" # Update casino_data_output with a confirmation message casino_message = f"Played {number_type.lower()} numbers: {', '.join(valid_numbers)}
" # Update spin_counter and sides_of_zero_display new_spin_counter = update_spin_counter() new_sides_of_zero = render_sides_of_zero_display() print(f"Played {number_type.lower()} numbers: {valid_numbers}") print(f"Updated state.last_spins: {state.last_spins}") return ( new_spins_display, # spins_display new_spins_display, # spins_textbox casino_message, # casino_data_output new_spin_counter, # spin_counter new_sides_of_zero # sides_of_zero_display ) except Exception as e: print(f"Error in play_specific_numbers: {str(e)}") return ( spins_display, spins_display, f"Error playing {number_type.lower()} numbers: {str(e)}
", update_spin_counter(), render_sides_of_zero_display() ) def clear_hot_cold_picks(type_label, current_spins_display): """Clear hot or cold numbers input.""" state.casino_data[f"{type_label.lower()}_numbers"] = [] success_msg = f"Cleared {type_label} Picks successfully" print(f"clear_hot_cold_picks: {success_msg}") return "", success_msg, update_spin_counter(), render_sides_of_zero_display(), current_spins_display def calculate_hit_percentages(last_spin_count): """Calculate hit percentages and generate BOTH Old Badges and New Charts.""" try: # --- 1. Data Collection --- last_spin_count = int(last_spin_count) if last_spin_count is not None else 36 last_spin_count = max(1, min(last_spin_count, 36)) last_spins = state.last_spins[-last_spin_count:] if state.last_spins else [] if not last_spins: return "No spins available for analysis.
" total_spins = len(last_spins) even_money_counts = {"Red": 0, "Black": 0, "Even": 0, "Odd": 0, "Low": 0, "High": 0} column_counts = {"1st Column": 0, "2nd Column": 0, "3rd Column": 0} dozen_counts = {"1st Dozen": 0, "2nd Dozen": 0, "3rd Dozen": 0} for spin in last_spins: try: num = int(spin) for name, numbers in EVEN_MONEY.items(): if num in numbers: even_money_counts[name] += 1 for name, numbers in COLUMNS.items(): if num in numbers: column_counts[name] += 1 for name, numbers in DOZENS.items(): if num in numbers: dozen_counts[name] += 1 except ValueError: continue max_even_money = max(even_money_counts.values()) if even_money_counts else 0 max_columns = max(column_counts.values()) if column_counts else 0 max_dozens = max(dozen_counts.values()) if dozen_counts else 0 # --- 2. OLD DISPLAY: Horizontal Badges --- old_html = 'Error calculating hit percentages.
" # Updated function with debug log DEBUG = True # Keep debugging enabled def summarize_spin_traits(last_spin_count): """Summarize traits for the last X spins as HTML badges, highlighting winners, hot streaks, and chopping patterns.""" try: if DEBUG: print(f"summarize_spin_traits: last_spin_count = {last_spin_count}") # Validate and clamp last_spin_count last_spin_count = int(last_spin_count) if last_spin_count is not None else 36 last_spin_count = max(1, min(last_spin_count, 36)) if DEBUG: print(f"summarize_spin_traits: After clamping, last_spin_count = {last_spin_count}") # Validate state if not hasattr(state, 'last_spins') or not isinstance(state.last_spins, list): if DEBUG: print(f"summarize_spin_traits: Invalid state.last_spins") return "Error: Spin data not initialized.
" last_spins = state.last_spins[-last_spin_count:] if state.last_spins else [] if DEBUG: print(f"summarize_spin_traits: last_spins = {last_spins}") if not last_spins: return "No spins available for analysis.
" # Validate bet mappings if not all(x in globals() for x in ['EVEN_MONEY', 'COLUMNS', 'DOZENS']): missing = [x for x in ['EVEN_MONEY', 'COLUMNS', 'DOZENS'] if x not in globals()] if DEBUG: print(f"summarize_spin_traits: Missing bet mappings: {missing}") return "Error: Bet mappings not defined.
" # Validate EVEN_MONEY mappings for Red and Black if "Red" not in EVEN_MONEY or "Black" not in EVEN_MONEY: if DEBUG: print(f"summarize_spin_traits: EVEN_MONEY missing Red or Black mappings") return "Error: EVEN_MONEY mappings incomplete.
" # Initialize counters and streaks even_money_counts = {"Red": 0, "Black": 0, "Even": 0, "Odd": 0, "Low": 0, "High": 0} column_counts = {"1st Column": 0, "2nd Column": 0, "3rd Column": 0} dozen_counts = {"1st Dozen": 0, "2nd Dozen": 0, "3rd Dozen": 0} number_counts = {} even_money_streaks = {key: {"current": 0, "max": 0, "last_hit": False, "spins": []} for key in even_money_counts} column_streaks = {key: {"current": 0, "max": 0, "last_hit": False, "spins": []} for key in column_counts} dozen_streaks = {key: {"current": 0, "max": 0, "last_hit": False, "spins": []} for key in dozen_counts} if DEBUG: print(f"summarize_spin_traits: Initialized counters and streaks") # Analyze spins for idx, spin in enumerate(last_spins): if DEBUG: print(f"summarize_spin_traits: Processing spin {idx}: {spin}") try: num = int(spin) if DEBUG: print(f"summarize_spin_traits: Converted spin to integer: {num}") # Reset last_hit flags for key in even_money_streaks: even_money_streaks[key]["last_hit"] = False for key in column_streaks: column_streaks[key]["last_hit"] = False for key in dozen_streaks: dozen_streaks[key]["last_hit"] = False if DEBUG: print(f"summarize_spin_traits: Reset last_hit flags for spin {num}") # Even Money Bets for name, numbers in EVEN_MONEY.items(): if num in numbers: even_money_counts[name] += 1 even_money_streaks[name]["last_hit"] = True even_money_streaks[name]["current"] += 1 even_money_streaks[name]["spins"].append(str(num)) if len(even_money_streaks[name]["spins"]) > even_money_streaks[name]["current"]: even_money_streaks[name]["spins"] = even_money_streaks[name]["spins"][-even_money_streaks[name]["current"]:] even_money_streaks[name]["max"] = max(even_money_streaks[name]["max"], even_money_streaks[name]["current"]) else: if not even_money_streaks[name]["last_hit"]: even_money_streaks[name]["current"] = 0 even_money_streaks[name]["spins"] = [] if DEBUG: print(f"summarize_spin_traits: Processed Even Money Bets for spin {num}") # Columns for name, numbers in COLUMNS.items(): if num in numbers: column_counts[name] += 1 column_streaks[name]["last_hit"] = True column_streaks[name]["current"] += 1 column_streaks[name]["spins"].append(str(num)) if len(column_streaks[name]["spins"]) > column_streaks[name]["current"]: column_streaks[name]["spins"] = column_streaks[name]["spins"][-column_streaks[name]["current"]:] column_streaks[name]["max"] = max(column_streaks[name]["max"], column_streaks[name]["current"]) else: if not column_streaks[name]["last_hit"]: column_streaks[name]["current"] = 0 column_streaks[name]["spins"] = [] if DEBUG: print(f"summarize_spin_traits: Processed Columns for spin {num}") # Dozens for name, numbers in DOZENS.items(): if num in numbers: dozen_counts[name] += 1 dozen_streaks[name]["last_hit"] = True dozen_streaks[name]["current"] += 1 dozen_streaks[name]["spins"].append(str(num)) if len(dozen_streaks[name]["spins"]) > dozen_streaks[name]["current"]: dozen_streaks[name]["spins"] = dozen_streaks[name]["spins"][-dozen_streaks[name]["current"]:] dozen_streaks[name]["max"] = max(dozen_streaks[name]["max"], dozen_streaks[name]["current"]) else: if not dozen_streaks[name]["last_hit"]: dozen_streaks[name]["current"] = 0 dozen_streaks[name]["spins"] = [] if DEBUG: print(f"summarize_spin_traits: Processed Dozens for spin {num}") number_counts[num] = number_counts.get(num, 0) + 1 if DEBUG: print(f"summarize_spin_traits: Processed Repeat Numbers for spin {num}") except ValueError as ve: if DEBUG: print(f"summarize_spin_traits: ValueError converting spin {spin} to integer: {str(ve)}") continue # Calculate max counts if DEBUG: print(f"summarize_spin_traits: Calculating max counts") max_even_money = max(even_money_counts.values()) if even_money_counts else 0 max_columns = max(column_counts.values()) if column_counts else 0 max_dozens = max(dozen_counts.values()) if dozen_counts else 0 if DEBUG: print(f"summarize_spin_traits: Max counts - Even Money: {max_even_money}, Columns: {max_columns}, Dozens: {max_dozens}") # Quick Trends and Betting Suggestions if DEBUG: print(f"summarize_spin_traits: Calculating Quick Trends") total_spins = len(last_spins) trends = [] suggestions = [] if total_spins > 0: all_counts = {**even_money_counts, **column_counts, **dozen_counts} dominant = max(all_counts.items(), key=lambda x: x[1], default=("None", 0)) if dominant[1] > 0: percentage = (dominant[1] / total_spins * 100) trends.append(("hot", f"{dominant[0]} dominates with {percentage:.1f}% hits")) # Add suggestion for dominant trait if percentage >= 40: # Suggest only if hit rate is significant suggestions.append(f"Bet on {dominant[0]} - {percentage:.1f}% hit rate in last {total_spins} spins!") all_streaks = {**even_money_streaks, **column_streaks, **dozen_streaks} longest_streak = max((v["current"] for v in all_streaks.values() if v["current"] > 1), default=0) if longest_streak > 1: streak_name = next(k for k, v in all_streaks.items() if v["current"] == longest_streak) streak_spins = ", ".join(all_streaks[streak_name]["spins"][-longest_streak:]) trends.append(("streak", f"{streak_name} on a {longest_streak}-spin streak (Spins: {streak_spins})")) # Add suggestion for streak if longest_streak >= 3: # Suggest for significant streaks suggestions.append(f"{streak_name} is hot - {longest_streak}/{total_spins} hits!") # Add cold trend for least hit trait least_hit = min(all_counts.items(), key=lambda x: x[1], default=("None", 0)) if least_hit[1] == 0 and least_hit[0] != "None": trends.append(("cold", f"{least_hit[0]} has no hits")) if DEBUG: print(f"summarize_spin_traits: Quick Trends calculated: {trends}, Suggestions: {suggestions}") # Calculate Red/Black Switches (Suggestion 9) switch_count = 0 switch_dots = [] recent_spins = last_spins[-6:] if len(last_spins) >= 6 else last_spins if DEBUG: print(f"summarize_spin_traits: Recent spins for switch alert: {recent_spins}") for i, spin in enumerate(recent_spins): try: num = int(spin) color = "green" if num == 0 else \ "red" if num in EVEN_MONEY["Red"] else \ "black" if num in EVEN_MONEY["Black"] else "unknown" switch_dots.append(color) if i > 0 and color != "green" and switch_dots[i-1] != "green" and color != switch_dots[i-1]: switch_count += 1 except ValueError: switch_dots.append("unknown") switch_class = " high-switches" if switch_count >= 4 else "" if DEBUG: print(f"summarize_spin_traits: Red/Black Switches: {switch_count}, Dots: {switch_dots}") # Calculate Dozen Shifts (Suggestion 10) dozen_counts_prev = {"1st Dozen": 0, "2nd Dozen": 0, "3rd Dozen": 0} dozen_counts_current = {"1st Dozen": 0, "2nd Dozen": 0, "3rd Dozen": 0} prev_spins = last_spins[-10:-5] if len(last_spins) >= 10 else last_spins[:5] if len(last_spins) >= 5 else [] current_spins = last_spins[-5:] if len(last_spins) >= 5 else last_spins for spin in prev_spins: try: num = int(spin) for name, numbers in DOZENS.items(): if num in numbers: dozen_counts_prev[name] += 1 except ValueError: continue for spin in current_spins: try: num = int(spin) for name, numbers in DOZENS.items(): if num in numbers: dozen_counts_current[name] += 1 except ValueError: continue dozen_shifts = {name: dozen_counts_current[name] - dozen_counts_prev[name] for name in dozen_counts} max_shift = max(dozen_shifts.values(), default=0) dominant_dozen = None dozen_class = "" if max_shift > 0: dominant_dozen = next(name for name, shift in dozen_shifts.items() if shift == max_shift) dozen_class = "d1" if dominant_dozen == "1st Dozen" else "d2" if dominant_dozen == "2nd Dozen" else "d3" if DEBUG: print(f"summarize_spin_traits: Dozen Shifts - Previous: {dozen_counts_prev}, Current: {dozen_counts_current}, Shifts: {dozen_shifts}, Dominant: {dominant_dozen}") # Build HTML if DEBUG: print(f"summarize_spin_traits: Building HTML") html = 'No significant trends detected yet.
' html += 'Error analyzing spin traits.
" def cache_analysis(spins, last_spin_count): """Cache the results of summarize_spin_traits to avoid redundant calculations.""" spins_list = state.last_spins if hasattr(state, 'last_spins') else [] if not spins_list and isinstance(spins, str) and spins.strip(): spins_list = [s.strip() for s in spins.split(",") if s.strip()] cache_key = f"{last_spin_count}_{hash(tuple(spins_list))}" if cache_key in state.analysis_cache: if DEBUG: print(f"cache_analysis: Cache hit for key {cache_key}") return state.analysis_cache[cache_key] # Limit cache size MAX_CACHE_SIZE = 100 if len(state.analysis_cache) >= MAX_CACHE_SIZE: oldest_key = next(iter(state.analysis_cache)) del state.analysis_cache[oldest_key] if DEBUG: print(f"cache_analysis: Removed oldest cache entry {oldest_key}") # Perform analysis result = summarize_spin_traits(last_spin_count) state.analysis_cache[cache_key] = result if DEBUG: print(f"cache_analysis: Cached result for key {cache_key}") return result def select_next_spin_top_pick(last_spin_count, trait_filter=None, trait_match_weight=100, secondary_match_weight=10, wheel_side_weight=5, section_weight=10, recency_weight=1, hit_bonus_weight=5, neighbor_weight=2): try: last_spin_count = int(last_spin_count) if last_spin_count is not None else 18 last_spin_count = max(1, min(last_spin_count, 36)) last_spins = state.last_spins[-last_spin_count:] if state.last_spins else [] if not last_spins: return "No spins available for analysis.
" # Log the spins being analyzed print(f"Analyzing last {last_spin_count} spins: {last_spins}") numbers = set(range(37)) hit_counts = {n: 0 for n in range(37)} last_positions = {n: -1 for n in range(37)} for i, spin in enumerate(last_spins): try: num = int(spin) hit_counts[num] += 1 last_positions[num] = i except ValueError: continue # Default to all traits if none specified or empty if trait_filter is None or not trait_filter: trait_filter = ["Red/Black", "Even/Odd", "Low/High", "Dozens", "Columns", "Wheel Sections", "Neighbors"] even_money_counts = {"Red": 0, "Black": 0, "Even": 0, "Odd": 0, "Low": 0, "High": 0} column_counts = {"1st Column": 0, "2nd Column": 0, "3rd Column": 0} dozen_counts = {"1st Dozen": 0, "2nd Dozen": 0, "3rd Dozen": 0} for spin in last_spins: try: num = int(spin) if "Red/Black" in trait_filter: if num in EVEN_MONEY["Red"]: even_money_counts["Red"] += 1 elif num in EVEN_MONEY["Black"]: even_money_counts["Black"] += 1 if "Even/Odd" in trait_filter: if num in EVEN_MONEY["Even"]: even_money_counts["Even"] += 1 elif num in EVEN_MONEY["Odd"]: even_money_counts["Odd"] += 1 if "Low/High" in trait_filter: if num in EVEN_MONEY["Low"]: even_money_counts["Low"] += 1 elif num in EVEN_MONEY["High"]: even_money_counts["High"] += 1 if "Dozens" in trait_filter: for name, nums in DOZENS.items(): if num in nums: dozen_counts[name] += 1 if "Columns" in trait_filter: for name, nums in COLUMNS.items(): if num in nums: column_counts[name] += 1 except ValueError: continue # Calculate percentages for included traits total_spins = len(last_spins) trait_percentages = {} if "Red/Black" in trait_filter: for trait in ["Red", "Black"]: trait_percentages[trait] = (even_money_counts[trait] / total_spins) * 100 if total_spins > 0 else 0 if "Even/Odd" in trait_filter: for trait in ["Even", "Odd"]: trait_percentages[trait] = (even_money_counts[trait] / total_spins) * 100 if total_spins > 0 else 0 if "Low/High" in trait_filter: for trait in ["Low", "High"]: trait_percentages[trait] = (even_money_counts[trait] / total_spins) * 100 if total_spins > 0 else 0 if "Dozens" in trait_filter: for trait in dozen_counts: trait_percentages[trait] = (dozen_counts[trait] / total_spins) * 100 if total_spins > 0 else 0 if "Columns" in trait_filter: for trait in column_counts: trait_percentages[trait] = (column_counts[trait] / total_spins) * 100 if total_spins > 0 else 0 # Sort traits by percentage (highest to lowest) sorted_traits = sorted(trait_percentages.items(), key=lambda x: (-x[1], x[0])) # Determine hottest traits (top non-conflicting traits) hottest_traits = [] seen_categories = set() for trait, percentage in sorted_traits: if trait in ["Red", "Black"]: if "Red-Black" in seen_categories: continue hottest_traits.append(trait) seen_categories.add("Red-Black") elif trait in ["Even", "Odd"]: if "Even-Odd" in seen_categories: continue hottest_traits.append(trait) seen_categories.add("Even-Odd") elif trait in ["Low", "High"]: if "Low-High" in seen_categories: continue hottest_traits.append(trait) seen_categories.add("Low-High") elif trait in ["1st Dozen", "2nd Dozen", "3rd Dozen"]: if "Dozens" in seen_categories: continue hottest_traits.append(trait) seen_categories.add("Dozens") elif trait in ["1st Column", "2nd Column", "3rd Column"]: if "Columns" in seen_categories: continue hottest_traits.append(trait) seen_categories.add("Columns") # Second best traits for tiebreakers second_best_traits = [] seen_categories = set() for trait, percentage in sorted_traits: if trait in hottest_traits: continue if trait in ["Red", "Black"]: if "Red-Black" in seen_categories: continue second_best_traits.append(trait) seen_categories.add("Red-Black") elif trait in ["Even", "Odd"]: if "Even-Odd" in seen_categories: continue second_best_traits.append(trait) seen_categories.add("Even-Odd") elif trait in ["Low", "High"]: if "Low-High" in seen_categories: continue second_best_traits.append(trait) seen_categories.add("Low-High") elif trait in ["1st Dozen", "2nd Dozen", "3rd Dozen"]: if "Dozens" in seen_categories: continue second_best_traits.append(trait) seen_categories.add("Dozens") elif trait in ["1st Column", "2nd Column", "3rd Column"]: if "Columns" in seen_categories: continue second_best_traits.append(trait) seen_categories.add("Columns") # Wheel side analysis (only if included) left_side = set(LEFT_OF_ZERO_EUROPEAN) right_side = set(RIGHT_OF_ZERO_EUROPEAN) left_hits = 0 right_hits = 0 if "Wheel Sections" in trait_filter: left_hits = sum(hit_counts[num] for num in left_side) right_hits = sum(hit_counts[num] for num in right_side) most_hit_side = "Left" if left_hits > right_hits else "Right" if right_hits > left_hits else "Both" betting_sections = { "Voisins du Zero": [22, 18, 29, 7, 28, 12, 35, 3, 26, 0, 32, 15, 19, 4, 21, 2, 25], "Orphelins": [17, 34, 6, 1, 20, 14, 31, 9], "Tiers du Cylindre": [27, 13, 36, 11, 30, 8, 23, 10, 5, 24, 16, 33] } section_hits = {name: 0 for name in betting_sections} section_last_pos = {name: -1 for name in betting_sections} if "Wheel Sections" in trait_filter: section_hits = {name: sum(hit_counts[num] for num in nums) for name, nums in betting_sections.items()} for name, nums in betting_sections.items(): for num in nums: if last_positions[num] > section_last_pos[name]: section_last_pos[name] = last_positions[num] sorted_sections = sorted(section_hits.items(), key=lambda x: (-x[1], -section_last_pos[x[0]])) top_section = sorted_sections[0][0] if sorted_sections and "Wheel Sections" in trait_filter else None neighbor_boost = {num: 0 for num in range(37)} if "Neighbors" in trait_filter: last_five = last_spins[-5:] if len(last_spins) >= 5 else last_spins last_five_set = set(last_five) for num in range(37): if num in NEIGHBORS_EUROPEAN: left, right = NEIGHBORS_EUROPEAN[num] if left is not None and str(left) in last_five_set: neighbor_boost[num] += 2 if right is not None and str(right) in last_five_set: neighbor_boost[num] += 2 # Score numbers based on the number of matching traits in order scores = [] for num in range(37): if num not in hit_counts or hit_counts[num] == 0: continue # Only consider numbers that appear in the spins # Count matching traits in order matching_traits = 0 for trait in hottest_traits: if trait in EVEN_MONEY and num in EVEN_MONEY[trait]: matching_traits += 1 elif trait in DOZENS and num in DOZENS[trait]: matching_traits += 1 elif trait in COLUMNS and num in COLUMNS[trait]: matching_traits += 1 # Secondary score for second best traits secondary_matches = 0 for trait in second_best_traits: if trait in EVEN_MONEY and num in EVEN_MONEY[trait]: secondary_matches += 1 elif trait in DOZENS and num in DOZENS[trait]: secondary_matches += 1 elif trait in COLUMNS and num in COLUMNS[trait]: secondary_matches += 1 # Additional scoring factors wheel_side_score = 0 if "Wheel Sections" in trait_filter: if most_hit_side == "Both" or (most_hit_side == "Left" and num in left_side) or (most_hit_side == "Right" and num in right_side): wheel_side_score = 1 # Will be scaled by weight section_score = 1 if top_section and num in betting_sections.get(top_section, []) else 0 recency_score = (last_spin_count - (last_positions[num] + 1)) if last_positions[num] >= 0 else 0 if last_positions[num] == last_spin_count - 1: recency_score = max(recency_score, 10) hit_bonus = 1 if hit_counts[num] > 0 else 0 neighbor_score = neighbor_boost[num] if "Neighbors" in trait_filter else 0 tiebreaker_score = 0 if num == 0: pass else: if num in EVEN_MONEY["Red"] and "Red/Black" in trait_filter: tiebreaker_score += even_money_counts["Red"] elif num in EVEN_MONEY["Black"] and "Red/Black" in trait_filter: tiebreaker_score += even_money_counts["Black"] if num in EVEN_MONEY["Even"] and "Even/Odd" in trait_filter: tiebreaker_score += even_money_counts["Even"] elif num in EVEN_MONEY["Odd"] and "Even/Odd" in trait_filter: tiebreaker_score += even_money_counts["Odd"] if num in EVEN_MONEY["Low"] and "Low/High" in trait_filter: tiebreaker_score += even_money_counts["Low"] elif num in EVEN_MONEY["High"] and "Low/High" in trait_filter: tiebreaker_score += even_money_counts["High"] if "Dozens" in trait_filter: for name, nums in DOZENS.items(): if num in nums: tiebreaker_score += dozen_counts[name] break if "Columns" in trait_filter: for name, nums in COLUMNS.items(): if num in nums: tiebreaker_score += column_counts[name] break # Apply configurable weights total_score = ( matching_traits * trait_match_weight + secondary_matches * secondary_match_weight + wheel_side_score * wheel_side_weight + section_score * section_weight + recency_score * recency_weight + hit_bonus * hit_bonus_weight + neighbor_score * neighbor_weight ) scores.append((num, total_score, matching_traits, secondary_matches, wheel_side_score, section_score, recency_score, hit_bonus, neighbor_score, tiebreaker_score)) # Sort by number of matching traits, then secondary matches, then tiebreaker, then recency scores.sort(key=lambda x: (-x[2], -x[3], -x[9], -x[6], -x[0])) # Ensure top 10 picks have at least as many matches as the 10th pick if len(scores) > 10: min_traits = sorted([x[2] for x in scores[:10]], reverse=True)[9] top_picks = [x for x in scores if x[2] >= min_traits][:10] else: top_picks = scores[:10] state.current_top_pick = top_picks[0][0] top_pick = top_picks[0][0] # Calculate confidence based on matching traits max_possible_traits = len(hottest_traits) top_traits_matched = top_picks[0][2] confidence = max(0, min(100, int((top_traits_matched / max_possible_traits) * 100))) if max_possible_traits > 0 else 0 characteristics = [] top_pick_int = int(top_pick) if top_pick_int == 0: characteristics.append("Green") elif "Red" in EVEN_MONEY and top_pick_int in EVEN_MONEY["Red"] and "Red/Black" in trait_filter: characteristics.append("Red") elif "Black" in EVEN_MONEY and top_pick_int in EVEN_MONEY["Black"] and "Red/Black" in trait_filter: characteristics.append("Black") if top_pick_int != 0: if "Even" in EVEN_MONEY and top_pick_int in EVEN_MONEY["Even"] and "Even/Odd" in trait_filter: characteristics.append("Even") elif "Odd" in EVEN_MONEY and top_pick_int in EVEN_MONEY["Odd"] and "Even/Odd" in trait_filter: characteristics.append("Odd") if "Low" in EVEN_MONEY and top_pick_int in EVEN_MONEY["Low"] and "Low/High" in trait_filter: characteristics.append("Low") elif "High" in EVEN_MONEY and top_pick_int in EVEN_MONEY["High"] and "Low/High" in trait_filter: characteristics.append("High") if "Dozens" in trait_filter: for name, nums in DOZENS.items(): if top_pick_int in nums: characteristics.append(name) break if "Columns" in trait_filter: for name, nums in COLUMNS.items(): if top_pick_int in nums: characteristics.append(name) break characteristics_str = ", ".join(characteristics) if characteristics else "No notable characteristics" color = colors.get(str(top_pick), "black") _, total_score, matching_traits, secondary_matches, wheel_side_score, section_score, recency_score, hit_bonus, neighbor_score, tiebreaker_score = top_picks[0] reasons = [] matched_traits = [] for trait in hottest_traits: if trait in EVEN_MONEY and top_pick in EVEN_MONEY[trait]: matched_traits.append(trait) elif trait in DOZENS and top_pick in DOZENS[trait]: matched_traits.append(trait) elif trait in COLUMNS and top_pick in COLUMNS[trait]: matched_traits.append(trait) if matched_traits: reasons.append(f"Matches the hottest traits: {', '.join(matched_traits)} (weight: {trait_match_weight})") if section_score > 0 and "Wheel Sections" in trait_filter: reasons.append(f"Located in the hottest wheel section: {top_section} (weight: {section_weight})") if recency_score > 0: last_pos = last_positions[top_pick] reasons.append(f"Recently appeared in the spin history (position {last_pos}) (weight: {recency_weight})") if hit_bonus > 0: reasons.append(f"Has appeared in the spin history (weight: {hit_bonus_weight})") if wheel_side_score > 0 and "Wheel Sections" in trait_filter: reasons.append(f"On the most hit side of the wheel: {most_hit_side} (weight: {wheel_side_weight})") if neighbor_score > 0 and "Neighbors" in trait_filter: neighbors_hit = [str(n) for n in NEIGHBORS_EUROPEAN.get(top_pick, (None, None)) if str(n) in last_five_set] reasons.append(f"Has recent neighbors in the last 5 spins: {', '.join(neighbors_hit)} (weight: {neighbor_weight})") if tiebreaker_score > 0: reasons.append(f"Boosted by aggregated trait scores (tiebreaker: {tiebreaker_score})") reasons_html = "No specific reasons available.
" last_five_spins = last_spins[-5:] if len(last_spins) >= 5 else last_spins last_five_spins_html = "" for spin in last_five_spins: spin_color = colors.get(str(spin), "black") last_five_spins_html += f'{spin}' top_5_html = "" for i, (num, total_score, matching_traits, secondary_matches, wheel_side_score, section_score, recency_score, hit_bonus, neighbor_score, tiebreaker_score) in enumerate(top_picks[1:10], 1): num_color = colors.get(str(num), "black") num_characteristics = [] if num == 0: num_characteristics.append("Green") elif "Red" in EVEN_MONEY and num in EVEN_MONEY["Red"] and "Red/Black" in trait_filter: num_characteristics.append("Red") elif "Black" in EVEN_MONEY and num in EVEN_MONEY["Black"] and "Red/Black" in trait_filter: num_characteristics.append("Black") if num != 0: if "Even" in EVEN_MONEY and num in EVEN_MONEY["Even"] and "Even/Odd" in trait_filter: num_characteristics.append("Even") elif "Odd" in EVEN_MONEY and num in EVEN_MONEY["Odd"] and "Even/Odd" in trait_filter: num_characteristics.append("Odd") if "Low" in EVEN_MONEY and num in EVEN_MONEY["Low"] and "Low/High" in trait_filter: num_characteristics.append("Low") elif "High" in EVEN_MONEY and num in EVEN_MONEY["High"] and "Low/High" in trait_filter: num_characteristics.append("High") if "Dozens" in trait_filter: for name, nums in DOZENS.items(): if num in nums: num_characteristics.append(name) break if "Columns" in trait_filter: for name, nums in COLUMNS.items(): if num in nums: num_characteristics.append(name) break num_characteristics_str = ", ".join(num_characteristics) if num_characteristics else "No notable characteristics" num_reasons = [] num_matched_traits = [] for trait in hottest_traits: if trait in EVEN_MONEY and num in EVEN_MONEY[trait]: num_matched_traits.append(trait) elif trait in DOZENS and num in DOZENS[trait]: num_matched_traits.append(trait) elif trait in COLUMNS and num in COLUMNS[trait]: num_matched_traits.append(trait) if num_matched_traits: num_reasons.append(f"Matches: {', '.join(num_matched_traits)}") if "Wheel Sections" in trait_filter: for section_name, nums in betting_sections.items(): if num in nums: num_reasons.append(f"In {section_name}") break if tiebreaker_score > 0: num_reasons.append(f"Tiebreaker: {tiebreaker_score}") num_reasons_str = ", ".join(num_reasons) if num_reasons else "No notable reasons" top_5_html += f'''Based on analysis of the last {last_spin_count} spins.
Error selecting top pick.
" # ------------------------------------------------------------------- # DE2D TRACKER LOGIC (TITANIUM v10.11: FIX VARIABLE SCOPE ERROR) # ------------------------------------------------------------------- def de2d_tracker_logic(miss_threshold=11, even_threshold=10, streak_threshold=9, pattern_x=8, voisins_threshold=8, tiers_threshold=9, left_threshold=7, right_threshold=7, ds_threshold=4, d17_threshold=6, corner_threshold=6, grind_active=False, grind_target="3rd Dozen"): """ Logic for the DE2D Tracker section. Version: TITANIUM v10.11. Updates: 1. CRITICAL FIX: Moved 'max_corner_miss' calculation up to prevent 'referenced before assignment' error. 2. Maintains all previous features (Spotlight, Flames, On Deck Radar). """ try: # ========================================================= # 1. SELF-HEALING STATE INITIALIZATION # ========================================================= if not hasattr(state, 'grind_step_index'): state.grind_step_index = 0 if not hasattr(state, 'grind_last_spin_count'): state.grind_last_spin_count = 0 if not hasattr(state, 'd17_list'): state.d17_list = [] if not hasattr(state, 'd17_locked'): state.d17_locked = False if not hasattr(state, 'last_spins') or state.last_spins is None: state.last_spins = [] # ========================================================= # 2. VARIABLE INITIALIZATION # ========================================================= config_html = "" spins_html = "" actions_section = "" visual_table = "" sequences_info_html = "" active_actions = [] highlight_targets = set() grind_targets = set() active_target_groups = [] on_deck_triggers = [] # List for triggers 1 spin away # ========================================================= # 3. CSS STYLES # ========================================================= inactive_style = "background-color: #34495e; color: #bdc3c7; font-size: 10px; border: 1px solid #2c3e50;" active_style = "background-color: #FFD700; color: #000000; font-weight: 900; font-size: 11px; border: 2px solid #FFC107; box-shadow: 0 0 5px #FFD700;" grind_style = "background-color: #2ecc71; color: white; font-weight: bold; font-size: 10px; border: 1px solid #27ae60;" rank1_style = "border: 3px solid #FFFF00 !important; box-shadow: 0 0 15px #FFFF00 !important; z-index: 10;" rank2_style = "border: 2px solid #00FFFF !important; box-shadow: 0 0 10px #00FFFF !important; z-index: 5;" rank3_style = "border: 2px solid #32CD32 !important; box-shadow: 0 0 8px #32CD32 !important;" # ========================================================= # 4. HELPER FUNCTIONS # ========================================================= def parse_arg(val, default): try: return int(val) if val is not None else default except: return default def get_status_style(is_active): if is_active: return "background: linear-gradient(135deg, #d32f2f, #ff5252); color: white; font-weight: bold; border: 2px solid #ff8a80; box-shadow: 0 0 10px rgba(255, 82, 82, 0.7); animation: pulse-red 1.5s infinite;" return "background: #f5f5f5; color: #777; border: 1px solid #ddd;" def get_counter_color(curr, thresh): if curr >= thresh: return "color: #fff; font-weight: bold; text-shadow: 0 0 2px black;" if curr >= thresh - 1: return "color: #d32f2f; font-weight: bold;" if curr >= thresh - 2: return "color: #f57c00; font-weight: bold;" return "color: #333;" def get_progress_bar_html(current, threshold): if threshold <= 0: threshold = 1 pct = min(100, (current / threshold) * 100) bar_color = "#4CAF50" if pct >= 50: bar_color = "#FFC107" if pct >= 80: bar_color = "#FF5722" if pct >= 100: bar_color = "#D32F2F" if pct >= 100: bar_color = "#fff" return f""" """ def format_seq(data_list): return " ".join([f"{item[0]}" for item in data_list]) def format_sequence_html(sequence, current_val, threshold): idx = current_val - threshold if idx < 0: idx = -1 if idx >= len(sequence): idx = len(sequence) - 1 html_parts = [] for i, val in enumerate(sequence): if i == idx: html_parts.append(f'{val}') else: html_parts.append(str(val)) return f"[{', '.join(html_parts)}]" def count_misses(target_set, spin_list, zero_is_miss=True): count = 0 for s in reversed(spin_list): if s in target_set: return count if s == 0 and not zero_is_miss: return count count += 1 return count def count_hits(target_set, spin_list): count = 0 for s in reversed(spin_list): if s in target_set: count += 1 elif s == 0: return count else: return count return count def count_hits_with_zero(target_set, spin_list): count = 0 for s in reversed(spin_list): if s in target_set or s == 0: count += 1 else: return count return count def count_frequency(target_set, spin_list): return sum(1 for s in spin_list if s in target_set) def get_header_color(title): if "MISSING" in title: return "#1976D2" if "STREAK" in title: return "#E64A19" if "EVEN" in title: return "#388E3C" if "PATTERN" in title: return "#7B1FA2" if "VOISINS" in title: return "#0097A7" if "TIERS" in title: return "#0288D1" if "SIDE" in title: return "#FBC02D"; if "5DS" in title: return "#C2185B" if "17" in title: return "#D32F2F" if "CORNER" in title: return "#FF9800" if "GRIND" in title: return "#2E7D32" return "#455A64" def get_text_color_for_header(title): if "SIDE" in title: return "#333" return "#FFF" def get_hottest_sector(spins): if not spins: return "3rd Dozen" d_counts = {d: count_frequency(set(nums), spins) for d, nums in DOZENS.items()} c_counts = {c: count_frequency(set(nums), spins) for c, nums in COLUMNS.items()} best_d = max(d_counts.items(), key=lambda x: x[1]) best_c = max(c_counts.items(), key=lambda x: x[1]) if best_d[1] == best_c[1]: return [best_d[0], best_c[0]] elif best_d[1] > best_c[1]: return best_d[0] else: return best_c[0] def get_grind_numbers(target): if isinstance(target, list): nums = set() for t in target: if t in DOZENS: nums.update(DOZENS[t]) elif t in COLUMNS: nums.update(COLUMNS[t]) return list(nums) if target in DOZENS: return DOZENS[target] elif target in COLUMNS: return COLUMNS[target] return [] def get_pattern_alert(spin_list, type="dozen"): mapped_tuples = [] for s in spin_list: cat = "0" if s == 0: cat = "0" elif type == "dozen": if s in DOZENS["1st Dozen"]: cat = "D1" elif s in DOZENS["2nd Dozen"]: cat = "D2" elif s in DOZENS["3rd Dozen"]: cat = "D3" else: if s in COLUMNS["1st Column"]: cat = "C1" elif s in COLUMNS["2nd Column"]: cat = "C2" elif s in COLUMNS["3rd Column"]: cat = "C3" mapped_tuples.append((cat, s)) categories = [t[0] for t in mapped_tuples] if len(categories) < pat_x + 10: return None target_pattern = categories[-pat_x:] search_limit = len(categories) - pat_x - pat_y match_idx = -1 for i in range(search_limit, -1, -1): if categories[i : i+pat_x] == target_pattern: match_idx = i break if match_idx != -1: return target_pattern, mapped_tuples[match_idx : match_idx+pat_x], mapped_tuples[match_idx+pat_x : match_idx+pat_x+pat_y] return None def generate_action_card(title, target, current_miss, wait_threshold, sequence, cost_per_unit, tooltip_nums=None, is_5ds=False, spots_override=None): step_index = current_miss - wait_threshold if step_index < 0: step_index = 0 if step_index >= len(sequence): step_index = len(sequence) - 1 unit_mult = sequence[step_index] # --- MATH CORRECTION FOR D17 --- if "17-NUMBER" in title: spots = 17 spot_name = "Num" p_unit = 0.01; d_unit = 0.10; D_unit = 1.00 p_total = unit_mult * p_unit; d_total = unit_mult * d_unit; D_total = unit_mult * D_unit p_per_spot = p_total / 17; d_per_spot = d_total / 17; D_per_spot = D_total / 17 else: if spots_override: spots = spots_override spot_name = "Line" if is_5ds else "Spot" else: spots = 1 spot_name = "Spot" if is_5ds: spots = 5; spot_name = "Line" elif "CORNER" in title: spots = 5; spot_name = "Crnr" elif "STREAK" in title: spots = 2; spot_name = "Doz" elif "SIDE" in title: spots = 25; spot_name = "Num" elif "VOISINS" in title: spots = 17; spot_name = "Num" elif "TIERS" in title: spots = 20; spot_name = "Num" p_unit = 0.01; p_per_spot = unit_mult * p_unit; p_total = p_per_spot * spots d_unit = 0.10; d_per_spot = unit_mult * d_unit; d_total = d_per_spot * spots D_unit = 1.00; D_per_spot = unit_mult * D_unit; D_total = D_per_spot * spots if "VOISINS" in title or "TIERS" in title or "SIDE" in title: p_total = unit_mult * p_unit * spots p_per_spot = unit_mult * p_unit d_total = unit_mult * d_unit * spots d_per_spot = unit_mult * d_unit D_total = unit_mult * D_unit * spots D_per_spot = unit_mult * D_unit mantras = ["Protect the Bankroll.", "Don't Chase Ghosts.", "Patience Pays.", "Sniper Mode On.", "Respect the Stop Loss.", "Stay Cool 🧊", "Trust the Math.", "Lock Profit Early."] import random daily_mantra = random.choice(mantras) header_bg = get_header_color(title) header_text = get_text_color_for_header(title) tooltip_html = "" if tooltip_nums: sorted_nums = sorted(list(tooltip_nums)) nums_str = ", ".join(map(str, sorted_nums)) tooltip_html = f'title="Cover: {nums_str}"' step_badge = f"STEP {step_index + 1}/{len(sequence)}" if "GRIND" in title: step_badge = f"STEP {current_miss + 1}/{len(sequence)}" seq_html = format_sequence_html(sequence, current_miss if "GRIND" in title else current_miss, wait_threshold if "GRIND" not in title else 0) extra_html = f"""| Unit | Per {spot_name} | Total Bet |
|---|---|---|
| 1¢ | ${p_per_spot:.2f} | ${p_total:.2f} |
| 10¢ | ${d_per_spot:.2f} | ${d_total:.2f} |
| $1 | ${D_per_spot:.2f} | ${D_total:.2f} |
No spin data available for suggestions.
" sorted_scores = sorted(state.scores.items(), key=lambda x: x[1], reverse=True) hot_numbers = [str(num) for num, score in sorted_scores[:5] if score > 0] cold_numbers = [str(num) for num, score in sorted_scores[-5:] if score >= 0] if not hot_numbers: hot_numbers = ["No hot numbers"] if not cold_numbers: cold_numbers = ["No cold numbers"] state.hot_suggestions = ", ".join(hot_numbers) state.cold_suggestions = ", ".join(cold_numbers) return state.hot_suggestions, state.cold_suggestions except Exception as e: print(f"suggest_hot_cold_numbers: Error: {str(e)}") return "", "Error generating suggestions.
" STRATEGIES = { "Hot Bet Strategy": {"function": hot_bet_strategy, "categories": ["even_money", "dozens", "columns", "streets", "corners", "six_lines", "splits", "sides", "numbers"]}, "Cold Bet Strategy": {"function": cold_bet_strategy, "categories": ["even_money", "dozens", "columns", "streets", "corners", "six_lines", "splits", "sides", "numbers"]}, "Best Even Money Bets": {"function": best_even_money_bets, "categories": ["even_money"]}, "Best Even Money Bets + Top Pick 18 Numbers": {"function": best_even_money_and_top_18, "categories": ["even_money", "numbers"]}, "Best Dozens": {"function": best_dozens, "categories": ["dozens"]}, "Best Dozens + Top Pick 18 Numbers": {"function": best_dozens_and_top_18, "categories": ["dozens", "numbers"]}, "Best Columns": {"function": best_columns, "categories": ["columns"]}, "Best Columns + Top Pick 18 Numbers": {"function": best_columns_and_top_18, "categories": ["columns", "numbers"]}, "Best Dozens + Best Even Money Bets + Top Pick 18 Numbers": {"function": best_dozens_even_money_and_top_18, "categories": ["dozens", "even_money", "numbers", "trends"]}, "Best Columns + Best Even Money Bets + Top Pick 18 Numbers": {"function": best_columns_even_money_and_top_18, "categories": ["columns", "even_money", "numbers", "trends"]}, "Fibonacci Strategy": {"function": fibonacci_strategy, "categories": ["dozens", "columns"]}, "Best Streets": {"function": best_streets, "categories": ["streets"]}, "Best Double Streets": {"function": best_double_streets, "categories": ["six_lines"]}, "Best Corners": {"function": best_corners, "categories": ["corners"]}, "Best Splits": {"function": best_splits, "categories": ["splits"]}, "Best Dozens + Best Streets": {"function": best_dozens_and_streets, "categories": ["dozens", "streets"]}, "Best Columns + Best Streets": {"function": best_columns_and_streets, "categories": ["columns", "streets"]}, "Non-Overlapping Double Street Strategy": {"function": non_overlapping_double_street_strategy, "categories": ["six_lines"]}, "Non-Overlapping Corner Strategy": {"function": non_overlapping_corner_strategy, "categories": ["corners"]}, "Romanowksy Missing Dozen": {"function": romanowksy_missing_dozen_strategy, "categories": ["dozens", "numbers"]}, "Fibonacci To Fortune": {"function": fibonacci_to_fortune_strategy, "categories": ["even_money", "dozens", "columns", "six_lines"]}, "3-8-6 Rising Martingale": {"function": three_eight_six_rising_martingale, "categories": ["streets"]}, "1 Dozen +1 Column Strategy": {"function": one_dozen_one_column_strategy, "categories": ["dozens", "columns"]}, "Top Pick 18 Numbers without Neighbours": {"function": top_pick_18_numbers_without_neighbours, "categories": ["numbers"]}, "Top Numbers with Neighbours (Tiered)": {"function": top_numbers_with_neighbours_tiered, "categories": ["numbers"]}, "Neighbours of Strong Number": {"function": neighbours_of_strong_number, "categories": ["neighbours"]} } # Line 1: Start of show_strategy_recommendations function (updated) def show_strategy_recommendations(strategy_name, neighbours_count, *args): """Generate strategy recommendations based on the selected strategy.""" try: print(f"show_strategy_recommendations: scores = {dict(state.scores)}") print(f"show_strategy_recommendations: even_money_scores = {dict(state.even_money_scores)}") print(f"show_strategy_recommendations: any_scores = {any(state.scores.values())}, any_even_money = {any(state.even_money_scores.values())}") print(f"show_strategy_recommendations: strategy_name = {strategy_name}, neighbours_count = {neighbours_count}, args = {args}") if strategy_name == "None": return "No strategy selected. Please choose a strategy to see recommendations.
" # If no spins yet, provide a default for "Best Even Money Bets" if not any(state.scores.values()) and not any(state.even_money_scores.values()): if strategy_name == "Best Even Money Bets": return "No spins yet. Default Even Money Bets to consider:
1. Red
2. Black
3. Even
Please analyze some spins first to generate scores.
" strategy_info = STRATEGIES[strategy_name] strategy_func = strategy_info["function"] if strategy_name == "Neighbours of Strong Number": try: neighbours_count = int(neighbours_count) strong_numbers_count = int(args[0]) if args else 1 # Assuming strong_numbers_count is first in args print(f"show_strategy_recommendations: Using neighbours_count = {neighbours_count}, strong_numbers_count = {strong_numbers_count}") except (ValueError, TypeError) as e: print(f"show_strategy_recommendations: Error converting inputs: {str(e)}, defaulting to 2 and 1.") neighbours_count = 2 strong_numbers_count = 1 result = strategy_func(neighbours_count, strong_numbers_count) # Handle the tuple return value for Neighbours of Strong Number if isinstance(result, tuple) and len(result) == 2: recommendations, _ = result # We only need the recommendations string for display else: recommendations = result elif strategy_name == "Dozen Tracker": # Dozen Tracker expects multiple arguments and returns a tuple result = strategy_func(*args) if isinstance(result, tuple) and len(result) == 3: recommendations, _, _ = result # Unpack the tuple, we only need the first element else: recommendations = result elif strategy_name == "Top Numbers Strategy": # Handle Top Numbers Strategy try: strong_numbers_count = int(args[0]) if args else 5 # Number of top numbers to show print(f"show_strategy_recommendations: Using strong_numbers_count = {strong_numbers_count} for Top Numbers Strategy") except (ValueError, TypeError) as e: print(f"show_strategy_recommendations: Error converting inputs: {str(e)}, defaulting to 5.") strong_numbers_count = 5 # Call the strategy function to get the top numbers top_numbers = strategy_func() # Assuming this returns a list of (number, score) tuples if not top_numbers: return "No top numbers available. Please analyze more spins.
" # Limit to strong_numbers_count and sort by score top_numbers = sorted(top_numbers, key=lambda x: x[1], reverse=True)[:strong_numbers_count] # Generate neighbors for each number html = "Here are the top numbers to consider based on recent spins:
" html += '| Number | Score | Neighbors | Number | Score | Neighbors | Number | Score | Neighbors |
|---|---|---|---|---|---|---|---|---|
| {number} | {score} | {', '.join(map(str, neighbors))} | " else: html += "" html += " |
Suggestions:
') elif line.strip() == "" and in_suggestions: in_suggestions = False html_lines.append('') elif in_suggestions: html_lines.append(f'{line}
') else: html_lines.append(f'{line}
') return ' tags and join with
for proper spacing
html_lines = [f"
{line}
" for line in lines] return "No spins yet.
', elem_classes=["last-spins-container"] ) last_spin_count = gr.Slider( label="", minimum=1, maximum=36, step=1, value=36, interactive=True, elem_classes="long-slider" ) # Updated CSS and Debounce Script for Last Spins gr.HTML(""" """) # 2. Row 2: European Roulette Table (unchanged) with gr.Group(): gr.Markdown("### European Roulette Table") table_layout = [ ["", "3", "6", "9", "12", "15", "18", "21", "24", "27", "30", "33", "36"], ["0", "2", "5", "8", "11", "14", "17", "20", "23", "26", "29", "32", "35"], ["", "1", "4", "7", "10", "13", "16", "19", "22", "25", "28", "31", "34"] ] with gr.Column(elem_classes="roulette-table"): for row in table_layout: with gr.Row(elem_classes="table-row"): for num in row: if num == "": gr.Button(value=" ", interactive=False, min_width=40, elem_classes="empty-button") else: color = colors.get(str(num), "black") is_selected = int(num) in state.selected_numbers btn_classes = [f"roulette-button", color] if is_selected: btn_classes.append("selected") btn = gr.Button( value=num, min_width=40, elem_classes=btn_classes ) btn.click( fn=add_spin, inputs=[gr.State(value=num), spins_display, last_spin_count], outputs=[spins_display, spins_textbox, last_spin_display, spin_counter, sides_of_zero_display] ).then( fn=format_spins_as_html, inputs=[spins_display, last_spin_count], outputs=[last_spin_display] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=calculate_hit_percentages, inputs=[last_spin_count], outputs=[hit_percentage_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=lambda: print(f"After add_spin: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) # New: Total Spins Section (Placed right after European Roulette Table) with gr.Row(): with gr.Column(scale=1, min_width=200): # Reference the already-defined spin_counter spin_counter # 3. Row 3: Last Spins Display and Show Last Spins Slider with gr.Row(): with gr.Column(): last_spin_display last_spin_count # 4. Row 4: Spin Controls (unchanged) with gr.Row(): with gr.Column(scale=1): undo_button = gr.Button("Undo Spins", elem_classes=["action-button"], elem_id="undo-spins-btn") with gr.Column(scale=1): generate_spins_button = gr.Button("Generate Random Spins", elem_classes=["action-button"]) with gr.Column(scale=1): toggle_trends_button = gr.Button( value="Hide Trends", # Initial string value elem_classes=["action-button"], elem_id="toggle-trends-btn" ) # 5. Row 5: Selected Spins Textbox (Updated to exclude spin_counter) with gr.Row(elem_id="selected-spins-row"): with gr.Column(scale=1, min_width=600): spins_textbox # Define strategy categories and choices strategy_categories = { "Trends": ["Cold Bet Strategy", "Hot Bet Strategy", "Best Dozens + Best Even Money Bets + Top Pick 18 Numbers", "Best Columns + Best Even Money Bets + Top Pick 18 Numbers"], "Even Money Strategies": ["Best Even Money Bets", "Best Even Money Bets + Top Pick 18 Numbers", "Fibonacci To Fortune"], "Dozen Strategies": ["1 Dozen +1 Column Strategy", "Best Dozens", "Best Dozens + Top Pick 18 Numbers", "Best Dozens + Best Even Money Bets + Top Pick 18 Numbers", "Best Dozens + Best Streets", "Fibonacci Strategy", "Romanowksy Missing Dozen"], "Column Strategies": ["1 Dozen +1 Column Strategy", "Best Columns", "Best Columns + Top Pick 18 Numbers", "Best Columns + Best Even Money Bets + Top Pick 18 Numbers", "Best Columns + Best Streets"], "Street Strategies": ["3-8-6 Rising Martingale", "Best Streets", "Best Columns + Best Streets", "Best Dozens + Best Streets"], "Double Street Strategies": ["Best Double Streets", "Non-Overlapping Double Street Strategy"], "Corner Strategies": ["Best Corners", "Non-Overlapping Corner Strategy"], "Split Strategies": ["Best Splits"], "Number Strategies": ["Top Numbers with Neighbours (Tiered)", "Top Pick 18 Numbers without Neighbours"], "Neighbours Strategies": ["Neighbours of Strong Number"] } category_choices = ["None"] + sorted(strategy_categories.keys()) # Define video categories matching strategy categories video_categories = { "Trends": [], "Even Money Strategies": [ { "title": "S.T.Y.W: Zero Jack 2-2-3 Roulette Strategy", "link": "https://youtu.be/I_F9Wys3Ww0" }, { "title": "S.T.Y.W: Fibonacci to Fortune (My Top Strategy) - Follow The Winner", "link": "https://youtu.be/bwa0FUk6Yps" }, { "title": "S.T.Y.W: Triple Entry Max Climax Strategy", "link": "https://youtu.be/64aq0GEPww0" } ], "Dozen Strategies": [ { "title": "S.T.Y.W: Dynamic Play: 1 Dozen with 4 Streets or 2 Double Streets?", "link": "https://youtu.be/8aMHrvuzBGU" }, { "title": "S.T.Y.W: Romanowsky Missing Dozen Strategy", "link": "https://youtu.be/YbBtum5WVCk" }, { "title": "S.T.Y.W: Victory Vortex (Dozen Domination)", "link": "https://youtu.be/aKGA_csI9lY" }, { "title": "S.T.Y.W: The Overlap Jackpot (4 Streets + 2 Dozens) Strategy", "link": "https://youtu.be/rTqdMQk4_I4" }, { "title": "S.T.Y.W: Fibonacci to Fortune (My Top Strategy) - Follow The Winner", "link": "https://youtu.be/bwa0FUk6Yps" }, { "title": "S.T.Y.W: Double Up: Dozen & Street Strategy", "link": "https://youtu.be/Hod5gxusAVE" }, { "title": "S.T.Y.W: Triple Entry Max Climax Strategy", "link": "https://youtu.be/64aq0GEPww0" } ], "Column Strategies": [ { "title": "S.T.Y.W: Zero Jack 2-2-3 Roulette Strategy", "link": "https://youtu.be/I_F9Wys3Ww0" }, { "title": "S.T.Y.W: Victory Vortex (Dozen Domination)", "link": "https://youtu.be/aKGA_csI9lY" }, { "title": "S.T.Y.W: Fibonacci to Fortune (My Top Strategy) - Follow The Winner", "link": "https://youtu.be/bwa0FUk6Yps" } ], "Street Strategies": [ { "title": "S.T.Y.W: Dynamic Play: 1 Dozen with 4 Streets or 2 Double Streets?", "link": "https://youtu.be/8aMHrvuzBGU" }, { "title": "S.T.Y.W: 3-8-6 Rising Martingale", "link": "https://youtu.be/-ZcEUOTHMzA" }, { "title": "S.T.Y.W: The Overlap Jackpot (4 Streets + 2 Dozens) Strategy", "link": "https://youtu.be/rTqdMQk4_I4" }, { "title": "S.T.Y.W: Double Up: Dozen & Street Strategy", "link": "https://youtu.be/Hod5gxusAVE" } ], "Double Street Strategies": [ { "title": "S.T.Y.W: Dynamic Play: 1 Dozen with 4 Streets or 2 Double Streets?", "link": "https://youtu.be/8aMHrvuzBGU" }, { "title": "S.T.Y.W: The Classic Five Double Street", "link": "https://youtu.be/XX7lSDElwWI" } ], "Corner Strategies": [ { "title": "S.T.Y.W: 4-Corners Strategy (Seq:1,1,2,5,8,17,28,50)", "link": "https://youtu.be/zw7eUllTDbg" } ], "Split Strategies": [ { "title": "S.T.Y.W: Triple Entry Max Climax Strategy", "link": "https://youtu.be/64aq0GEPww0" } ], "Number Strategies": [ { "title": "The Pulse Wheel Strategy (6 Numbers +1 Neighbours)", "link": "https://youtu.be/UBajAwUXWS0" }, { "title": "Eighteen Strong Numbers with No Neighbours Strategy", "link": "https://youtu.be/8Nmbi8KmY9c" } ], "Neighbours Strategies": [ { "title": "The Pulse Wheel Strategy (6 Numbers +1 Neighbours)", "link": "https://youtu.be/UBajAwUXWS0" }, { "title": "Triad Spin Strategy: 87.53% (Modified Makarov-Biarritz)", "link": "https://youtu.be/ADhCvxNiWVc" } ] } # 6. Row 6: Analyze Spins, Clear Spins, and Clear All Buttons with gr.Row(): with gr.Column(scale=2): analyze_button = gr.Button("Analyze Spins", elem_classes=["action-button", "green-btn"], interactive=True) with gr.Column(scale=1): clear_spins_button = gr.Button("Clear Spins", elem_classes=["clear-spins-btn", "small-btn"]) with gr.Column(scale=1): clear_all_button = gr.Button("Clear All", elem_classes=["clear-spins-btn", "small-btn"]) # 7. Row 7: Dynamic Roulette Table and Strategy Recommendations with gr.Row(elem_classes="dynamic-table-strategy-row"): # Column for Strategy Recommendations (Left Side) with gr.Column(scale=2, min_width=450, elem_classes="strategy-recommendations-container"): gr.Markdown("### Strategy Recommendations") # Wrap the entire section in a div with class "strategy-card" with gr.Row(elem_classes="strategy-card"): with gr.Column(scale=1): # Use a single column to stack elements vertically with gr.Row(): category_dropdown = gr.Dropdown( label="Select Category", choices=category_choices, value="Even Money Strategies", allow_custom_value=False, elem_id="select-category" ) strategy_dropdown = gr.Dropdown( label="Select Strategy", choices=strategy_categories["Even Money Strategies"], value="Best Even Money Bets", allow_custom_value=False, elem_id="strategy-dropdown" ) reset_strategy_button = gr.Button("Reset Category & Strategy", elem_classes=["action-button"]) neighbours_count_slider = gr.Slider( label="Number of Neighbors (Left + Right)", minimum=1, maximum=5, step=1, value=1, interactive=True, visible=False, elem_classes="long-slider" ) strong_numbers_count_slider = gr.Slider( label="Strong Numbers to Highlight (Neighbours Strategy)", minimum=1, maximum=18, step=1, value=1, interactive=True, visible=False, elem_classes="long-slider" ) strategy_output = gr.HTML( label="Strategy Recommendations", value=show_strategy_recommendations("Best Even Money Bets", 2, 1), elem_classes=["strategy-box"] ) # Column for Dynamic Roulette Table (Right Side) with gr.Column(scale=4, min_width=700, elem_classes="dynamic-table-container"): gr.Markdown("### Dynamic Roulette Table", elem_id="dynamic-table-heading") dynamic_table_output = gr.HTML( label="Dynamic Table", value=create_dynamic_table(strategy_name="Best Even Money Bets"), elem_classes=["scrollable-table", "large-table"] ) # 7.1. Row 7.1: Dozen Tracker with gr.Row(): with gr.Column(scale=3): with gr.Accordion("Create Dozen/Even Bet Triggers", open=False, elem_id="dozen-tracker"): gr.HTML(""" """) with gr.Accordion("Dozen Triggers", open=False, elem_id="dozen-triggers"): dozen_tracker_spins_dropdown = gr.Dropdown( label="Number of Spins to Track", choices=["3", "4", "5", "6", "10", "15", "20", "25", "30", "40", "50", "75", "100", "150", "200"], value="5", interactive=True ) dozen_tracker_consecutive_hits_dropdown = gr.Dropdown( label="Alert on Consecutive Dozen Hits", choices=["3", "4", "5"], value="3", interactive=True ) dozen_tracker_alert_checkbox = gr.Checkbox( label="Enable Consecutive Dozen Hits Alert", value=False, interactive=True ) dozen_tracker_sequence_length_dropdown = gr.Dropdown( label="Sequence Length to Match (X)", choices=["3", "4", "5"], value="4", interactive=True ) dozen_tracker_follow_up_spins_dropdown = gr.Dropdown( label="Follow-Up Spins to Track (Y)", choices=["3", "4", "5", "6", "7", "8", "9", "10"], value="5", interactive=True ) dozen_tracker_sequence_alert_checkbox = gr.Checkbox( label="Enable Sequence Matching Alert", value=False, interactive=True ) dozen_tracker_output = gr.HTML( label="Dozen Tracker", value="Select the number of spins to track and analyze spins to see the Dozen history.
" ) dozen_tracker_sequence_output = gr.HTML( label="Sequence Matching Results", value="Enable sequence matching to see results here.
" ) with gr.Accordion("Even Money", open=False, elem_id="even-money-tracker"): even_money_tracker_spins_dropdown = gr.Dropdown( label="Number of Spins to Track", choices=["1", "2", "3", "4", "5", "6", "10", "15", "20", "25", "30", "40", "50", "75", "100", "150", "200"], value="5", interactive=True ) even_money_tracker_consecutive_hits_dropdown = gr.Dropdown( label="Alert on Consecutive Even Money Hits", choices=["1", "2", "3", "4", "5"], value="3", interactive=True ) even_money_tracker_combination_mode_dropdown = gr.Dropdown( label="Combination Mode", choices=["And", "Or"], value="And", interactive=True ) even_money_tracker_identical_traits_checkbox = gr.Checkbox( label="Track Consecutive Identical Traits", value=False, interactive=True ) even_money_tracker_consecutive_identical_dropdown = gr.Dropdown( label="Number of Consecutive Identical Traits", choices=["1", "2", "3", "4", "5"], value="2", interactive=True ) with gr.Row(): even_money_tracker_red_checkbox = gr.Checkbox(label="Red", value=False, interactive=True) even_money_tracker_black_checkbox = gr.Checkbox(label="Black", value=False, interactive=True) even_money_tracker_even_checkbox = gr.Checkbox(label="Even", value=False, interactive=True) even_money_tracker_odd_checkbox = gr.Checkbox(label="Odd", value=False, interactive=True) even_money_tracker_low_checkbox = gr.Checkbox(label="Low", value=False, interactive=True) even_money_tracker_high_checkbox = gr.Checkbox(label="High", value=False, interactive=True) even_money_tracker_alert_checkbox = gr.Checkbox( label="Enable Even Money Hits Alert", value=False, interactive=True ) even_money_tracker_output = gr.HTML( label="Even Money Tracker", value="Select categories to track and analyze spins to see even money bet history.
" ) with gr.Column(scale=2): pass # 8. Row 8: Betting Progression Tracker with gr.Accordion("Betting Progression Tracker", open=False, elem_id="betting-progression", elem_classes=["betting-progression"]): gr.HTML(""" """) with gr.Row(): bankroll_input = gr.Number(label="Bankroll", value=1000) base_unit_input = gr.Number(label="Base Unit", value=10) stop_loss_input = gr.Number(label="Stop Loss", value=-500) stop_win_input = gr.Number(label="Stop Win", value=200) target_profit_input = gr.Number(label="Target Profit (Units)", value=10, step=1) with gr.Row(): bet_type_dropdown = gr.Dropdown( label="Bet Type", choices=["Even Money", "Dozens", "Columns", "Streets", "Straight Bets"], value="Even Money" ) progression_dropdown = gr.Dropdown( label="Progression", choices=[ "Martingale", "Fibonacci", "Triple Martingale", "Ladder", "D’Alembert", "Double After a Win", "+1 Win / -1 Loss", "+2 Win / -1 Loss", "Double Loss / +50% Win", "Victory Vortex V.2" ], value="Martingale" ) with gr.Row(): win_button = gr.Button("Win") lose_button = gr.Button("Lose") reset_progression_button = gr.Button("Reset Progression") reset_bankroll_button = gr.Button("Reset Bankroll") with gr.Row(): bankroll_output = gr.Textbox(label="Current Bankroll", value="1000", interactive=False) current_bet_output = gr.Textbox(label="Current Bet", value="10", interactive=False) next_bet_output = gr.Textbox(label="Next Bet", value="10", interactive=False) with gr.Row(): message_output = gr.Textbox(label="Message", value="Start with base bet of 10 on Even Money (Martingale)", interactive=False) status_output = gr.HTML(label="Status", value='No casino data entered yet.
", elem_classes=["fade-in"] ) with gr.Accordion("Hot and Cold Numbers", open=False, elem_id="hot-cold-numbers"): with gr.Row(): gr.HTML('') hot_numbers_input = gr.Textbox( label="Hot Numbers (1 to 10 comma-separated numbers, e.g., 1, 3, 5, 7, 9)", value="", interactive=True, placeholder="Enter 1 to 10 hot numbers" ) hot_suggestions = gr.Textbox( label="Suggested Hot Numbers (based on recent spins)", value="", interactive=False, elem_classes=["suggestion-box"] ) gr.Button("Use Suggested Hot Numbers", elem_classes=["action-button", "suggestion-btn"]).click( fn=lambda: state.hot_suggestions, inputs=[], outputs=[hot_numbers_input] ) with gr.Row(): gr.HTML('') cold_numbers_input = gr.Textbox( label="Cold Numbers (1 to 10 comma-separated numbers, e.g., 2, 4, 6, 8, 10)", value="", interactive=True, placeholder="Enter 1 to 10 cold numbers" ) cold_suggestions = gr.Textbox( label="Suggested Cold Numbers (based on recent spins)", value="", interactive=False, elem_classes=["suggestion-box"] ) gr.Button("Use Suggested Cold Numbers", elem_classes=["action-button", "suggestion-btn"]).click( fn=lambda: state.cold_suggestions, inputs=[], outputs=[cold_numbers_input] ) with gr.Row(): play_hot_button = gr.Button("Play Hot Numbers", elem_classes=["action-button", "play-btn"]) play_cold_button = gr.Button("Play Cold Numbers", elem_classes=["action-button", "play-btn"]) with gr.Row(): clear_hot_button = gr.Button("Clear Hot Picks", elem_classes=["action-button", "clear-btn"]) clear_cold_button = gr.Button("Clear Cold Picks", elem_classes=["action-button", "clear-btn"]) # 9. Row 9: Color Code Key (Collapsible, with Color Pickers Inside) with gr.Accordion("Color Code Key", open=False, elem_id="color-code-key"): gr.HTML(""" """) with gr.Row(): top_color_picker = gr.ColorPicker( label="Top Tier Color", value="rgba(255, 255, 0, 0.5)", interactive=True, elem_id="top-color-picker" ) middle_color_picker = gr.ColorPicker( label="Middle Tier Color", value="rgba(0, 255, 255, 0.5)", interactive=True ) lower_color_picker = gr.ColorPicker( label="Lower Tier Color", value="rgba(0, 255, 0, 0.5)", interactive=True ) reset_colors_button = gr.Button("Reset Colors", elem_classes=["action-button"]) color_code_output = gr.HTML(label="Color Code Key") # 10. Row 10: Analysis Outputs (Collapsible, Renumbered) with gr.Accordion("Spin Logic Reactor 🧠", open=False, elem_id="spin-analysis"): gr.HTML(""" """) with gr.Row(elem_classes=["spin-analysis-row"]): spin_analysis_output = gr.Textbox( label="", value="", interactive=False, lines=5 ) with gr.Accordion("Strongest Numbers Tables", open=False, elem_id="strongest-numbers-table"): gr.HTML(""" """) with gr.Row(elem_classes=["strongest-numbers-row"]): with gr.Column(): straight_up_html = gr.HTML(label="Strongest Numbers", elem_classes="scrollable-table") with gr.Column(): top_18_html = gr.HTML(label="Top 18 Strongest Numbers (Sorted Lowest to Highest)", elem_classes="scrollable-table") with gr.Row(): strongest_numbers_dropdown = gr.Dropdown( label="Select Number of Strongest Numbers", choices=["3", "6", "9", "12", "15", "18", "21", "24", "27", "30", "33"], value="3", allow_custom_value=False, interactive=True, elem_id="strongest-numbers-dropdown", visible=False # Hide the dropdown ) strongest_numbers_output = gr.Textbox( label="Strongest Numbers (Sorted Lowest to Highest)", value="", lines=2, visible=False # Hide the textbox ) with gr.Accordion("Aggregated Scores", open=False, elem_id="aggregated-scores"): gr.HTML(""" """) with gr.Row(elem_classes=["aggregated-scores-row"]): with gr.Column(): with gr.Accordion("Even Money Bets", open=False): even_money_output = gr.Textbox(label="Even Money Bets", lines=10, max_lines=50) with gr.Column(): with gr.Accordion("Dozens", open=False): dozens_output = gr.Textbox(label="Dozens", lines=10, max_lines=50) with gr.Row(elem_classes=["aggregated-scores-row"]): with gr.Column(): with gr.Accordion("Columns", open=False): columns_output = gr.Textbox(label="Columns", lines=10, max_lines=50) with gr.Column(): with gr.Accordion("Streets", open=False): streets_output = gr.Textbox(label="Streets", lines=10, max_lines=50) with gr.Row(elem_classes=["aggregated-scores-row"]): with gr.Column(): with gr.Accordion("Corners", open=False): corners_output = gr.Textbox(label="Corners", lines=10, max_lines=50) with gr.Column(): with gr.Accordion("Double Streets", open=False): six_lines_output = gr.Textbox(label="Double Streets", lines=10, max_lines=50) with gr.Row(elem_classes=["aggregated-scores-row"]): with gr.Column(): with gr.Accordion("Splits", open=False): splits_output = gr.Textbox(label="Splits", lines=10, max_lines=50) with gr.Column(): with gr.Accordion("Sides of Zero", open=False): sides_output = gr.Textbox(label="Sides of Zero", lines=10, max_lines=50) # In the "Save/Load Session" accordion with gr.Accordion("Save/Load Session", open=False, elem_id="save-load-session"): with gr.Row(elem_classes=["save-load-row"]): # Text input for the file name session_name_input = gr.Textbox( label="Session File Name", placeholder="Enter session name (e.g., MySession)", value="WheelPulse_Session", interactive=True, elem_id="session-name-input" ) save_button = gr.Button("Save Session", elem_id="save-session-btn") load_input = gr.File(label="Upload Session", file_types=[".json"], elem_id="upload-session") save_output = gr.File(label="Download Session", elem_id="download-session") gr.HTML( ''' ''' ) # 11. Row 11: Top Strategies with WheelPulse by S.T.Y.W (Moved to be Independent) with gr.Row(): with gr.Column(): with gr.Accordion("Top Strategies with WheelPulse by S.T.Y.W 📈🎥", open=False, elem_id="top-strategies"): gr.HTML(""" """) gr.Markdown("### Explore Strategies Through Videos") video_category_dropdown = gr.Dropdown( label="Select Video Category", choices=sorted(video_categories.keys()), value="Dozen Strategies", allow_custom_value=False, elem_id="video-category-dropdown" ) video_dropdown = gr.Dropdown( label="Select Video", choices=[video["title"] for video in video_categories["Dozen Strategies"]], value=video_categories["Dozen Strategies"][0]["title"] if video_categories["Dozen Strategies"] else None, allow_custom_value=False, elem_id="video-dropdown" ) video_output = gr.HTML( label="Video", value=f'' if video_categories["Dozen Strategies"] else "Select a category and video to watch.
" ) # Feedback & Suggestions section removed # CSS (end of the previous section, for context) gr.HTML(""" """) print("CSS Updated") # Shepherd.js Tour Script gr.HTML(""" """) # Event Handlers try: spins_textbox.change( fn=validate_spins_input, inputs=[spins_textbox], outputs=[spins_display, last_spin_display] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=analyze_spins, inputs=[spins_display, strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider], outputs=[ spin_analysis_output, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, dynamic_table_output, strategy_output, sides_of_zero_display ] ).then( fn=update_spin_counter, inputs=[], outputs=[spin_counter] ).then( fn=dozen_tracker, inputs=[dozen_tracker_spins_dropdown, dozen_tracker_consecutive_hits_dropdown, dozen_tracker_alert_checkbox, dozen_tracker_sequence_length_dropdown, dozen_tracker_follow_up_spins_dropdown, dozen_tracker_sequence_alert_checkbox], outputs=[gr.State(), dozen_tracker_output, dozen_tracker_sequence_output] ).then( fn=even_money_tracker, inputs=[ even_money_tracker_spins_dropdown, even_money_tracker_consecutive_hits_dropdown, even_money_tracker_alert_checkbox, even_money_tracker_combination_mode_dropdown, even_money_tracker_red_checkbox, even_money_tracker_black_checkbox, even_money_tracker_even_checkbox, even_money_tracker_odd_checkbox, even_money_tracker_low_checkbox, even_money_tracker_high_checkbox, even_money_tracker_identical_traits_checkbox, even_money_tracker_consecutive_identical_dropdown ], outputs=[gr.State(), even_money_tracker_output] ).then( fn=summarize_spin_traits, # Use summarize_spin_traits directly for now inputs=[last_spin_count], outputs=[traits_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, # Add voisins_slider to the list inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After spins_textbox change: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in spins_textbox.change handler: {str(e)}") gr.Warning(f"Error during spin analysis: {str(e)}") try: spins_display.change( fn=update_spin_counter, inputs=[], outputs=[spin_counter] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=calculate_hit_percentages, inputs=[last_spin_count], outputs=[hit_percentage_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, # Add voisins_slider to the list inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After spins_display change: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in spins_display.change handler: {str(e)}") try: clear_spins_button.click( fn=clear_spins, inputs=[], outputs=[spins_display, spins_textbox, spin_analysis_output, last_spin_display, spin_counter, sides_of_zero_display] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=calculate_hit_percentages, inputs=[last_spin_count], outputs=[hit_percentage_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, # Add voisins_slider to the list inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After clear_spins_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in clear_spins_button.click handler: {str(e)}") try: clear_all_button.click( fn=clear_all, inputs=[], outputs=[ spins_display, spins_textbox, spin_analysis_output, last_spin_display, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, spin_counter, sides_of_zero_display ] ).then( fn=clear_outputs, inputs=[], outputs=[ spin_analysis_output, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, dynamic_table_output, strategy_output, color_code_output ] ).then( fn=dozen_tracker, inputs=[ dozen_tracker_spins_dropdown, dozen_tracker_consecutive_hits_dropdown, dozen_tracker_alert_checkbox, dozen_tracker_sequence_length_dropdown, dozen_tracker_follow_up_spins_dropdown, dozen_tracker_sequence_alert_checkbox ], outputs=[gr.State(), dozen_tracker_output, dozen_tracker_sequence_output] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, # Add voisins_slider to the list inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After clear_all_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in clear_all_button.click handler: {str(e)}") try: generate_spins_button.click( fn=generate_random_spins, inputs=[gr.State(value="5"), spins_display, last_spin_count], outputs=[spins_display, spins_textbox, spin_analysis_output, spin_counter, sides_of_zero_display] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, # Add voisins_slider to the list inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After generate_spins_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in generate_spins_button.click handler: {str(e)}") # Line 1: Slider change handler (updated) try: last_spin_count.change( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=calculate_hit_percentages, inputs=[last_spin_count], outputs=[hit_percentage_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, # Add voisins_slider to the list inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After last_spin_count change: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in last_spin_count.change handler: {str(e)}") def update_strategy_dropdown(category): if category == "None": return gr.update(choices=["None"], value="None") return gr.update(choices=strategy_categories[category], value=strategy_categories[category][0]) try: category_dropdown.change( fn=update_strategy_dropdown, inputs=category_dropdown, outputs=strategy_dropdown ) except Exception as e: print(f"Error in category_dropdown.change handler: {str(e)}") try: reset_strategy_button.click( fn=reset_strategy_dropdowns, inputs=[], outputs=[category_dropdown, strategy_dropdown, strategy_dropdown] ).then( fn=lambda category: gr.update(choices=strategy_categories[category], value=strategy_categories[category][0]), inputs=[category_dropdown], outputs=[strategy_dropdown] ) except Exception as e: print(f"Error in reset_strategy_button.click handler: {str(e)}") def toggle_neighbours_slider(strategy_name): is_visible = strategy_name == "Neighbours of Strong Number" return ( gr.update(visible=is_visible), gr.update(visible=is_visible) ) # New: Orchestrating function to combine analysis steps def orchestrate_analysis(spins_display, strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, dozen_consecutive_hits, dozen_alert, dozen_sequence_length, dozen_follow_up_spins, dozen_sequence_alert, even_money_spins, even_money_consecutive_hits, even_money_alert, even_money_combination_mode, red, black, even, odd, low, high, identical_traits, consecutive_identical, top_color, middle_color, lower_color): """Orchestrate analysis, producing all outputs in one pass with scores always reset.""" import time start_time = time.time() # Run analysis (scores are always reset in analyze_spins) spins_analysis, even_money, dozens, columns, streets, corners, six_lines, splits, sides, straight_up, top_18, strongest_numbers = analyze_spins(spins_display, strategy, neighbours_count, strong_numbers_count) # Run trackers and dynamic table dozen_text, dozen_html, dozen_sequence_html = dozen_tracker( dozen_tracker_spins, dozen_consecutive_hits, dozen_alert, dozen_sequence_length, dozen_follow_up_spins, dozen_sequence_alert ) even_money_text, even_money_html = even_money_tracker( even_money_spins, even_money_consecutive_hits, even_money_alert, even_money_combination_mode, red, black, even, odd, low, high, identical_traits, consecutive_identical ) dynamic_table = create_dynamic_table( strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color ) color_code = create_color_code_table() print(f"Analysis completed in {time.time() - start_time:.3f} seconds") return ( spins_analysis, even_money, dozens, columns, streets, corners, six_lines, splits, sides, straight_up, top_18, strongest_numbers, dynamic_table, show_strategy_recommendations(strategy, neighbours_count, strong_numbers_count), render_sides_of_zero_display(), dozen_text, dozen_html, dozen_sequence_html, even_money_text, even_money_html, color_code, analysis_cache.value ) try: strategy_dropdown.change( fn=toggle_neighbours_slider, inputs=[strategy_dropdown], outputs=[neighbours_count_slider, strong_numbers_count_slider] ).then( fn=show_strategy_recommendations, inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider], outputs=[strategy_output] ).then( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: (print(f"Updating Dynamic Table with Strategy: {strategy}, Neighbours Count: {neighbours_count}, Strong Numbers Count: {strong_numbers_count}, Dozen Tracker Spins: {dozen_tracker_spins}, Colors: {top_color}, {middle_color}, {lower_color}"), create_dynamic_table(strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color))[-1], inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ) except Exception as e: print(f"Error in strategy_dropdown.change handler: {str(e)}") # --------------------------------------------------------- # FIXED EVENT LISTENERS (With d17_strategy_slider included everywhere) # --------------------------------------------------------- # 1. Analyze Button try: analyze_button.click( fn=analyze_spins, inputs=[ spins_display, strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, dozen_tracker_consecutive_hits_dropdown, dozen_tracker_alert_checkbox, dozen_tracker_sequence_length_dropdown, dozen_tracker_follow_up_spins_dropdown, dozen_tracker_sequence_alert_checkbox, even_money_tracker_spins_dropdown, even_money_tracker_consecutive_hits_dropdown, even_money_tracker_alert_checkbox, even_money_tracker_combination_mode_dropdown, even_money_tracker_red_checkbox, even_money_tracker_black_checkbox, even_money_tracker_even_checkbox, even_money_tracker_odd_checkbox, even_money_tracker_low_checkbox, even_money_tracker_high_checkbox, even_money_tracker_identical_traits_checkbox, even_money_tracker_consecutive_identical_dropdown ], outputs=[ spin_analysis_output, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, dynamic_table_output, strategy_output, sides_of_zero_display ] ).then( fn=lambda: ("", ""), inputs=[], outputs=[dynamic_table_output, strategy_output] ).then( fn=update_casino_data, inputs=[ spins_count_dropdown, even_percent, odd_percent, red_percent, black_percent, low_percent, high_percent, dozen1_percent, dozen2_percent, dozen3_percent, col1_percent, col2_percent, col3_percent, use_winners_checkbox ], outputs=[casino_data_output] ).then( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: create_dynamic_table( strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color ), inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ).then( fn=create_color_code_table, inputs=[], outputs=[color_code_output] ).then( fn=dozen_tracker, inputs=[ dozen_tracker_spins_dropdown, dozen_tracker_consecutive_hits_dropdown, dozen_tracker_alert_checkbox, dozen_tracker_sequence_length_dropdown, dozen_tracker_follow_up_spins_dropdown, dozen_tracker_sequence_alert_checkbox ], outputs=[gr.State(), dozen_tracker_output, dozen_tracker_sequence_output] ).then( fn=even_money_tracker, inputs=[ even_money_tracker_spins_dropdown, even_money_tracker_consecutive_hits_dropdown, even_money_tracker_alert_checkbox, even_money_tracker_combination_mode_dropdown, even_money_tracker_red_checkbox, even_money_tracker_black_checkbox, even_money_tracker_even_checkbox, even_money_tracker_odd_checkbox, even_money_tracker_low_checkbox, even_money_tracker_high_checkbox, even_money_tracker_identical_traits_checkbox, even_money_tracker_consecutive_identical_dropdown ], outputs=[gr.State(), even_money_tracker_output] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=calculate_hit_percentages, inputs=[last_spin_count], outputs=[hit_percentage_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After analyze_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in analyze_button.click handler: {str(e)}") gr.Warning(f"Error during analysis: {str(e)}") # 2. Save Session Button try: save_button.click( fn=save_session, inputs=[session_name_input], outputs=[save_output] ) except Exception as e: print(f"Error in save_button.click handler: {str(e)}") # 3. Load Session Input try: load_input.change( fn=load_session, inputs=[load_input, strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider], outputs=[ spins_display, spins_textbox, spin_analysis_output, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, dynamic_table_output, strategy_output ] ).then( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: create_dynamic_table( strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color ), inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=create_color_code_table, inputs=[], outputs=[color_code_output] ).then( fn=dozen_tracker, inputs=[dozen_tracker_spins_dropdown, dozen_tracker_consecutive_hits_dropdown, dozen_tracker_alert_checkbox, dozen_tracker_sequence_length_dropdown, dozen_tracker_follow_up_spins_dropdown, dozen_tracker_sequence_alert_checkbox], outputs=[gr.State(), dozen_tracker_output, dozen_tracker_sequence_output] ).then( fn=even_money_tracker, inputs=[even_money_tracker_spins_dropdown, even_money_tracker_consecutive_hits_dropdown, even_money_tracker_alert_checkbox, even_money_tracker_combination_mode_dropdown, even_money_tracker_red_checkbox, even_money_tracker_black_checkbox, even_money_tracker_even_checkbox, even_money_tracker_odd_checkbox, even_money_tracker_low_checkbox, even_money_tracker_high_checkbox, even_money_tracker_identical_traits_checkbox, even_money_tracker_consecutive_identical_dropdown], outputs=[gr.State(), even_money_tracker_output] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=calculate_hit_percentages, inputs=[last_spin_count], outputs=[hit_percentage_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After load_input change: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in load_input.change handler: {str(e)}") # 4. Undo Button try: undo_button.click( fn=undo_last_spin, inputs=[spins_display, gr.State(value=1), strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider], outputs=[ spin_analysis_output, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, spins_textbox, spins_display, dynamic_table_output, strategy_output, color_code_output, spin_counter, sides_of_zero_display ] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: create_dynamic_table( strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color ), inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ).then( fn=dozen_tracker, inputs=[dozen_tracker_spins_dropdown, dozen_tracker_consecutive_hits_dropdown, dozen_tracker_alert_checkbox, dozen_tracker_sequence_length_dropdown, dozen_tracker_follow_up_spins_dropdown, dozen_tracker_sequence_alert_checkbox], outputs=[gr.State(), dozen_tracker_output, dozen_tracker_sequence_output] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After undo_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in undo_button.click handler: {str(e)}") # 5. Neighbours Count Slider try: neighbours_count_slider.change( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: create_dynamic_table(strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color), inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ).then( fn=show_strategy_recommendations, inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider], outputs=[strategy_output] ) except Exception as e: print(f"Error in neighbours_count_slider.change handler: {str(e)}") # 6. Strong Numbers Count Slider try: strong_numbers_count_slider.change( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: create_dynamic_table(strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color), inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ).then( fn=show_strategy_recommendations, inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider], outputs=[strategy_output] ) except Exception as e: print(f"Error in strong_numbers_count_slider.change handler: {str(e)}") # 7. Reset Colors Button try: reset_colors_button.click( fn=reset_colors, inputs=[], outputs=[top_color_picker, middle_color_picker, lower_color_picker] ).then( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: create_dynamic_table(strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color), inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ) except Exception as e: print(f"Error in reset_colors_button.click handler: {str(e)}") # 8. Toggle Trends Button try: toggle_trends_button.click( fn=toggle_trends, inputs=[show_trends_state, toggle_trends_label], outputs=[show_trends_state, toggle_trends_label, toggle_trends_button] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After toggle_trends_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in toggle_trends_button.click handler: {str(e)}") # 9. Color Pickers (Top, Middle, Lower) try: top_color_picker.change( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: create_dynamic_table(strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color), inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ) except Exception as e: print(f"Error in top_color_picker.change handler: {str(e)}") try: middle_color_picker.change( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: create_dynamic_table(strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color), inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ) except Exception as e: print(f"Error in middle_color_picker.change handler: {str(e)}") try: lower_color_picker.change( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: create_dynamic_table(strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color), inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ) except Exception as e: print(f"Error in lower_color_picker.change handler: {str(e)}") # 10. Dozen Tracker Dropdowns/Checkboxes try: dozen_inputs = [dozen_tracker_spins_dropdown, dozen_tracker_consecutive_hits_dropdown, dozen_tracker_alert_checkbox, dozen_tracker_sequence_length_dropdown, dozen_tracker_follow_up_spins_dropdown, dozen_tracker_sequence_alert_checkbox] for inp in dozen_inputs: inp.change( fn=dozen_tracker, inputs=dozen_inputs, outputs=[gr.State(), dozen_tracker_output, dozen_tracker_sequence_output] ).then( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: create_dynamic_table(strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color), inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ) except Exception as e: print(f"Error in dozen_tracker inputs handler: {str(e)}") # 11. Even Money Tracker Dropdowns/Checkboxes try: even_money_inputs = [ even_money_tracker_spins_dropdown, even_money_tracker_consecutive_hits_dropdown, even_money_tracker_alert_checkbox, even_money_tracker_combination_mode_dropdown, even_money_tracker_red_checkbox, even_money_tracker_black_checkbox, even_money_tracker_even_checkbox, even_money_tracker_odd_checkbox, even_money_tracker_low_checkbox, even_money_tracker_high_checkbox, even_money_tracker_identical_traits_checkbox, even_money_tracker_consecutive_identical_dropdown ] for inp in even_money_inputs: inp.change( fn=even_money_tracker, inputs=even_money_inputs, outputs=[gr.State(), even_money_tracker_output] ) except Exception as e: print(f"Error in even_money_tracker inputs handler: {str(e)}") # 12. Casino Data Inputs (Dropdowns + Checkbox) casino_inputs = [ spins_count_dropdown, even_percent, odd_percent, red_percent, black_percent, low_percent, high_percent, dozen1_percent, dozen2_percent, dozen3_percent, col1_percent, col2_percent, col3_percent, use_winners_checkbox ] try: for inp in casino_inputs: inp.change( fn=update_casino_data, inputs=casino_inputs, outputs=[casino_data_output] ).then( fn=lambda strategy, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color: create_dynamic_table(strategy if strategy != "None" else None, neighbours_count, strong_numbers_count, dozen_tracker_spins, top_color, middle_color, lower_color), inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ) except Exception as e: print(f"Error in casino data inputs handler: {str(e)}") # 13. Reset Casino Data Button try: reset_casino_data_button.click( fn=lambda: ( "100", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", "00", False, "", "", "Casino data reset to defaults.
" ), inputs=[], outputs=[ spins_count_dropdown, even_percent, odd_percent, red_percent, black_percent, low_percent, high_percent, dozen1_percent, dozen2_percent, dozen3_percent, col1_percent, col2_percent, col3_percent, use_winners_checkbox, hot_numbers_input, cold_numbers_input, casino_data_output ] ).then( fn=create_dynamic_table, inputs=[strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider, dozen_tracker_spins_dropdown, top_color_picker, middle_color_picker, lower_color_picker], outputs=[dynamic_table_output] ) except Exception as e: print(f"Error in reset_casino_data_button.click handler: {str(e)}") # 14. Play Hot/Cold Buttons try: play_hot_button.click( fn=play_specific_numbers, inputs=[hot_numbers_input, gr.State(value="Hot"), spins_display, last_spin_count], outputs=[spins_display, spins_textbox, casino_data_output, spin_counter, sides_of_zero_display] ).then( fn=sync_spins_display, inputs=[spins_display], outputs=[spins_display] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=analyze_spins, inputs=[spins_display, strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider], outputs=[ spin_analysis_output, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, dynamic_table_output, strategy_output, sides_of_zero_display ] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=calculate_hit_percentages, inputs=[last_spin_count], outputs=[hit_percentage_display] ).then( fn=suggest_hot_cold_numbers, inputs=[], outputs=[hot_suggestions, cold_suggestions] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After play_hot_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in play_hot_button.click handler: {str(e)}") try: play_cold_button.click( fn=play_specific_numbers, inputs=[cold_numbers_input, gr.State(value="Cold"), spins_display, last_spin_count], outputs=[spins_display, spins_textbox, casino_data_output, spin_counter, sides_of_zero_display] ).then( fn=sync_spins_display, inputs=[spins_display], outputs=[spins_display] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=analyze_spins, inputs=[spins_display, strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider], outputs=[ spin_analysis_output, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, dynamic_table_output, strategy_output, sides_of_zero_display ] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=calculate_hit_percentages, inputs=[last_spin_count], outputs=[hit_percentage_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After play_cold_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in play_cold_button.click handler: {str(e)}") # 15. Clear Hot/Cold Buttons try: clear_hot_button.click( fn=clear_hot_cold_picks, inputs=[gr.State(value="Hot"), spins_display], outputs=[hot_numbers_input, casino_data_output, spin_counter, sides_of_zero_display, spins_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After clear_hot_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in clear_hot_button.click handler: {str(e)}") try: clear_cold_button.click( fn=clear_hot_cold_picks, inputs=[gr.State(value="Cold"), spins_display], outputs=[cold_numbers_input, casino_data_output, spin_counter, sides_of_zero_display, spins_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After clear_cold_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in clear_cold_button.click handler: {str(e)}") # 16. Spins Textbox/Display Changes (FIXED: Prevents Double Execution & Freezing) # 1. Textbox Input: ONLY Validates and Updates State (Lightweight) try: spins_textbox.change( fn=validate_spins_input, inputs=[spins_textbox], outputs=[spins_display, last_spin_display] ) # Note: We removed the .then() chain here. Updating 'spins_display' # automatically triggers the 'spins_display.change' listener below. except Exception as e: print(f"Error in spins_textbox.change handler: {str(e)}") # 2. State Change: The Single Source of Truth (Heavy Logic runs ONCE here) try: spins_display.change( fn=update_spin_counter, inputs=[], outputs=[spin_counter] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=analyze_spins, inputs=[spins_display, strategy_dropdown, neighbours_count_slider, strong_numbers_count_slider], outputs=[ spin_analysis_output, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, dynamic_table_output, strategy_output, sides_of_zero_display ] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=calculate_hit_percentages, inputs=[last_spin_count], outputs=[hit_percentage_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( # FIXED: Includes all 10 inputs for the new DE2D Logic fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=dozen_tracker, inputs=[dozen_tracker_spins_dropdown, dozen_tracker_consecutive_hits_dropdown, dozen_tracker_alert_checkbox, dozen_tracker_sequence_length_dropdown, dozen_tracker_follow_up_spins_dropdown, dozen_tracker_sequence_alert_checkbox], outputs=[gr.State(), dozen_tracker_output, dozen_tracker_sequence_output] ).then( fn=even_money_tracker, inputs=[ even_money_tracker_spins_dropdown, even_money_tracker_consecutive_hits_dropdown, even_money_tracker_alert_checkbox, even_money_tracker_combination_mode_dropdown, even_money_tracker_red_checkbox, even_money_tracker_black_checkbox, even_money_tracker_even_checkbox, even_money_tracker_odd_checkbox, even_money_tracker_low_checkbox, even_money_tracker_high_checkbox, even_money_tracker_identical_traits_checkbox, even_money_tracker_consecutive_identical_dropdown ], outputs=[gr.State(), even_money_tracker_output] ).then( fn=lambda: print(f"State Updated: Analysis Complete."), inputs=[], outputs=[] ) except Exception as e: print(f"Error in spins_display.change handler: {str(e)}") try: clear_spins_button.click( fn=clear_spins, inputs=[], outputs=[spins_display, spins_textbox, spin_analysis_output, last_spin_display, spin_counter, sides_of_zero_display] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=calculate_hit_percentages, inputs=[last_spin_count], outputs=[hit_percentage_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( # FIXED: Added d17_strategy_slider fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After clear_spins_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in clear_spins_button.click handler: {str(e)}") try: clear_all_button.click( fn=clear_all, inputs=[], outputs=[ spins_display, spins_textbox, spin_analysis_output, last_spin_display, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, spin_counter, sides_of_zero_display ] ).then( fn=clear_outputs, inputs=[], outputs=[ spin_analysis_output, even_money_output, dozens_output, columns_output, streets_output, corners_output, six_lines_output, splits_output, sides_output, straight_up_html, top_18_html, strongest_numbers_output, dynamic_table_output, strategy_output, color_code_output ] ).then( fn=dozen_tracker, inputs=[dozen_tracker_spins_dropdown, dozen_tracker_consecutive_hits_dropdown, dozen_tracker_alert_checkbox, dozen_tracker_sequence_length_dropdown, dozen_tracker_follow_up_spins_dropdown, dozen_tracker_sequence_alert_checkbox], outputs=[gr.State(), dozen_tracker_output, dozen_tracker_sequence_output] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( # FIXED: Added d17_strategy_slider fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After clear_all_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in clear_all_button.click handler: {str(e)}") try: generate_spins_button.click( fn=generate_random_spins, inputs=[gr.State(value="5"), spins_display, last_spin_count], outputs=[spins_display, spins_textbox, spin_analysis_output, spin_counter, sides_of_zero_display] ).then( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( # FIXED: Added d17_strategy_slider fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After generate_spins_button click: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in generate_spins_button.click handler: {str(e)}") try: last_spin_count.change( fn=lambda spins_display, count, show_trends: format_spins_as_html(spins_display, count, show_trends), inputs=[spins_display, last_spin_count, show_trends_state], outputs=[last_spin_display] ).then( fn=summarize_spin_traits, inputs=[last_spin_count], outputs=[traits_display] ).then( fn=calculate_hit_percentages, inputs=[last_spin_count], outputs=[hit_percentage_display] ).then( fn=select_next_spin_top_pick, inputs=[top_pick_spin_count], outputs=[top_pick_display] ).then( # FIXED: Added d17_strategy_slider fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After last_spin_count change: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in last_spin_count.change handler: {str(e)}") # Toggle Labouchere try: progression_dropdown.change( fn=toggle_labouchere, inputs=[progression_dropdown], outputs=[] # No output needed for hidden element management in this snippet ) except Exception as e: print(f"Error in progression_dropdown.change handler: {str(e)}") # 17. Weight Inputs for Top Pick for weight_input in [ trait_match_weight, secondary_match_weight, wheel_side_weight, section_weight, recency_weight, hit_bonus_weight, neighbor_weight ]: try: weight_input.change( fn=select_next_spin_top_pick, inputs=[ top_pick_spin_count, trait_filter, trait_match_weight, secondary_match_weight, wheel_side_weight, section_weight, recency_weight, hit_bonus_weight, neighbor_weight ], outputs=[top_pick_display] ).then( # FIXED: Added d17_strategy_slider fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After weight change: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in weight_input.change handler: {str(e)}") # 18. Trait Filter try: trait_filter.change( fn=select_next_spin_top_pick, inputs=[ top_pick_spin_count, trait_filter, trait_match_weight, secondary_match_weight, wheel_side_weight, section_weight, recency_weight, hit_bonus_weight, neighbor_weight ], outputs=[top_pick_display] ).then( # FIXED: Added grind_active_checkbox and grind_target_dropdown fn=de2d_tracker_logic, inputs=[miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown], outputs=[de2d_output] ).then( fn=lambda: print(f"After trait_filter change: state.last_spins = {state.last_spins}"), inputs=[], outputs=[] ) except Exception as e: print(f"Error in trait_filter.change handler: {str(e)}") # 19. Reset Weights try: reset_weights_button.click( fn=lambda spin_count, traits: ( 100, 10, 5, 10, 1, 5, 2, select_next_spin_top_pick(spin_count, traits, 100, 10, 5, 10, 1, 5, 2) ), inputs=[top_pick_spin_count, trait_filter], outputs=[ trait_match_weight, secondary_match_weight, wheel_side_weight, section_weight, recency_weight, hit_bonus_weight, neighbor_weight, top_pick_display ] ) except Exception as e: print(f"Error in reset_weights_button.click handler: {str(e)}") # --- NEW: Reset Grind Button Handler --- def reset_grind_step(miss, even, streak, pattern, voisins, tiers, left, right, ds, d17, corner, active, target): state.grind_step_index = 0 state.grind_last_spin_count = len(state.last_spins) # Sync spin count so it doesn't auto-advance # Re-run logic to update display immediately return de2d_tracker_logic(miss, even, streak, pattern, voisins, tiers, left, right, ds, d17, corner, active, target) try: reset_grind_button.click( fn=reset_grind_step, inputs=[ miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown ], outputs=[de2d_output] ) except Exception as e: print(f"Error in reset_grind_button.click handler: {str(e)}") # 20. DE2D Sliders (The final catch-all for slider changes) try: # UPDATED: de2d_inputs now includes the grind controls de2d_inputs = [ miss_slider, even_slider, streak_slider, pattern_slider, voisins_slider, tiers_slider, left_side_slider, right_side_slider, ds_strategy_slider, d17_strategy_slider, corner_strategy_slider, grind_active_checkbox, grind_target_dropdown ] miss_slider.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) even_slider.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) streak_slider.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) pattern_slider.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) voisins_slider.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) tiers_slider.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) left_side_slider.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) right_side_slider.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) ds_strategy_slider.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) d17_strategy_slider.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) corner_strategy_slider.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) # Also trigger logic when Grind controls change grind_active_checkbox.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) grind_target_dropdown.change(fn=de2d_tracker_logic, inputs=de2d_inputs, outputs=[de2d_output]) except Exception as e: print(f"Error in DE2D slider handlers: {str(e)}") # Launch the interface print("Starting Gradio launch...") demo.launch() print("Gradio launch completed.")