lotto_tom75
Advanced Premium Member
=======================================================
BOT INTELLIGENTE v16 - CLEAR STATS
=======================================================
DATI ESTRAZIONI:
• Database: /kaggle/input/estrazionilotto-aggiornate-al-20-1-2026
• Estrazioni caricate: 7143
-------------------------------------------------------
PARAMETRI DI RICERCA:
• Pool Numeri Base: 20
• Lunghezza Gruppo: 18 - 20 (dinamica)
• Ruote Unite: da 1 a 3 (dinamica)
* Ruote analizzate : ['BA','CA','FI','GE','MI','NA','PA','RO','TO','VE']
(tolta NZ perchè accorciava troppo il dataset)
* Sorte di ricerca: 2-3-4 (dinamica)
* Sorte di verifica: 2 (fissa)
* Range verifica: 4 (fissa)
• Range Ritardo: 10 - 300 (dinamico)
-------------------------------------------------------
OBIETTIVI:
• Minimo Eventi: 800
• Minimo Successo: 99.0%
=======================================================
>>> Inizializzazione...
Best:100.0%(296):
12629/? [04:27<00:00, 42.73it/s, L=19, R=3, Sg=280, Sr=4, St=]
★ 452 (92.7%) | L:19 R2 Sg34
★ 74 (94.6%) | L:18 R2 Sg54
★ 71 (95.8%) | L:18 R2 Sg54
★ 142 (96.5%) | L:19 R2 Sg280
★ 81 (98.8%) | L:20 R2 Sg280
★ 179 (98.9%) | L:18 R2 Sg300
★ 108 (99.1%) | L:19 R2 Sg300
★ 183 (100.0%) | L:18 R3 Sg300
★ 193 (100.0%) | L:18 R3 Sg270
★ 195 (100.0%) | L:18 R3 Sg280
★ 223 (100.0%) | L:18 R3 Sg285
★ 241 (100.0%) | L:18 R3 Sg280
★ 250 (100.0%) | L:18 R3 Sg260
★ 296 (100.0%) | L:18 R3 Sg260
...
Sta continuando lo scavo... con sola CPU

Relativo code per kagglisti e pythoniani... (rigorosamente frutto di vibe coding con google ai studio)
Cercherò di mettere qui sotto la versione sempre + aggiornata dello script lotto bot "intelligente"
Sarebbe bello che chi lo usasse e trovasse magari i parametri e la configurazione utopica top "100% +" con tutti i casi positivi e magari colpi rimanenti <= 16 x s1 o xs2 la condividesse qui sotto... (incluso ovviamente il sottoscritto). La ricerca e gli scavi continuano...
In questa versione v32 si ha la possibilità di usare qualsivoglia matrice caricata in input oppure qualsivoglia gruppo base hardcoded (implementato nel codice). Inoltre si ha la possibilità a fine analisi di vedere i massimi generali di tutta la ricerca divisi in IN (dentro i casi winner) e in abs (absolute = inclusi i casi negativi) . Questo al fine di facilitare poi la configurazione delle successive analoghe ricerche cercando di rientrare con quei valori massimi nel 100% teorico delle stesse auspicando di trovare relativi colpi rimanenti teorici minimi più contenuti possibili.
Buon divertimento... pythoniani e klagghiani e hugginfaciani in ascolto...
. Ringrazio per i like gli amici lottopython e silvix
ps: ovviamente come tutti i prg e sw (sopratutto quelli vibe codati) potrebbe avere bugs e problemi operativi ma il bello... credo stia anche nello scovarli insieme e cercare di risolvere anche quelli...
nb: il dataset archivio estrazioni deve essere nella forma : estrazioni-BA.txt ecc... fino a estrazioni-NZ.txt contenenti le estrazioni in formato numerico a doppia cifra con lo 0 davanti per i numeri da 1 a 9 , con cinque numeri intervallati da carattere punto e con le estrazioni recenti in alto e quelle vecchie in basso.
=======================================================
• Database: /kaggle/input/estrazionilotto-aggiornate-al-20-1-2026
• Estrazioni caricate: 7143
-------------------------------------------------------
• Pool Numeri Base: 20
• Lunghezza Gruppo: 18 - 20 (dinamica)
• Ruote Unite: da 1 a 3 (dinamica)
* Ruote analizzate : ['BA','CA','FI','GE','MI','NA','PA','RO','TO','VE']
(tolta NZ perchè accorciava troppo il dataset)
* Sorte di ricerca: 2-3-4 (dinamica)
* Sorte di verifica: 2 (fissa)
* Range verifica: 4 (fissa)
• Range Ritardo: 10 - 300 (dinamico)
-------------------------------------------------------
• Minimo Eventi: 800
• Minimo Successo: 99.0%
=======================================================
>>> Inizializzazione...
Best:100.0%(296):
12629/? [04:27<00:00, 42.73it/s, L=19, R=3, Sg=280, Sr=4, St=]
★ 452 (92.7%) | L:19 R2 Sg34
★ 74 (94.6%) | L:18 R2 Sg54
★ 71 (95.8%) | L:18 R2 Sg54
★ 142 (96.5%) | L:19 R2 Sg280
★ 81 (98.8%) | L:20 R2 Sg280
★ 179 (98.9%) | L:18 R2 Sg300
★ 108 (99.1%) | L:19 R2 Sg300
★ 183 (100.0%) | L:18 R3 Sg300
★ 193 (100.0%) | L:18 R3 Sg270
★ 195 (100.0%) | L:18 R3 Sg280
★ 223 (100.0%) | L:18 R3 Sg285
★ 241 (100.0%) | L:18 R3 Sg280
★ 250 (100.0%) | L:18 R3 Sg260
★ 296 (100.0%) | L:18 R3 Sg260
...
Sta continuando lo scavo... con sola CPU
Relativo code per kagglisti e pythoniani... (rigorosamente frutto di vibe coding con google ai studio)
Cercherò di mettere qui sotto la versione sempre + aggiornata dello script lotto bot "intelligente"
Sarebbe bello che chi lo usasse e trovasse magari i parametri e la configurazione utopica top "100% +" con tutti i casi positivi e magari colpi rimanenti <= 16 x s1 o xs2 la condividesse qui sotto... (incluso ovviamente il sottoscritto). La ricerca e gli scavi continuano...
In questa versione v32 si ha la possibilità di usare qualsivoglia matrice caricata in input oppure qualsivoglia gruppo base hardcoded (implementato nel codice). Inoltre si ha la possibilità a fine analisi di vedere i massimi generali di tutta la ricerca divisi in IN (dentro i casi winner) e in abs (absolute = inclusi i casi negativi) . Questo al fine di facilitare poi la configurazione delle successive analoghe ricerche cercando di rientrare con quei valori massimi nel 100% teorico delle stesse auspicando di trovare relativi colpi rimanenti teorici minimi più contenuti possibili.
Codice:
# 🤖 lotto BOT INTELLIGENTE v32 - SAFETY INPUT MODE
import numpy as np
import pandas as pd
import os
import time
import random
import json
import copy
import re
import math
from itertools import combinations
from numba import njit, prange
from tqdm.notebook import tqdm
from IPython.display import Audio, display, HTML
# ============================================================
# 0. FIX VISUALIZZAZIONE KAGGLE (FULL WIDTH)
# ============================================================
display(HTML("""
<style>
.container { width:100% !important; }
div.output_area { width: 100% !important; }
div.output_area pre {
white-space: pre-wrap;
word-wrap: break-word;
width: 100%;
overflow-x: hidden;
}
.widget-area { width: 100% !important; }
</style>
"""))
# ============================================================
# 1. CONFIGURAZIONE INPUT (BLINDATA v32)
# ============================================================
# --- SELEZIONE MODALITÀ ---
# Imposta questa variabile su 'FILE' oppure 'MANUALE'
# Attenzione: Python è case-sensitive, ma il codice ora gestisce spazi e maiuscole.
TIPO_INPUT = 'MANUALE'
# TIPO_INPUT = 'FILE'
# ------------------------------------------------------------
# OPZIONE A: LISTA MANUALE (Se TIPO_INPUT = 'MANUALE')
# Inserisci le tue righe qui sotto.
# ------------------------------------------------------------
MATRICE_MANUALE = [
# Esempio fornito:
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90]
# Puoi aggiungere altre righe qui sotto:
#
]
# ------------------------------------------------------------
# OPZIONE B: FILE (Se TIPO_INPUT = 'FILE')
# ------------------------------------------------------------
PATH_FILE_MATRICE = "/kaggle/input/14ineabsxesuttenzdal1871/solo14ineabsxEsuTTeNZdal1871solonumeri.txt"
# ------------------------------------------------------------
# IMPOSTAZIONI GENERALI
# ------------------------------------------------------------
RIGA_DA_ANALIZZARE = -2 # -2 = Batch, -1 = Merge, 0..N = Riga Specifica
TIMEOUT_MINUTI_PER_RIGA = 1
SOGLIA_COLPI_RIMANENTI = 9
GRUPPO_BASE_BACKUP = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90]
# ============================================================
# 2. OBIETTIVI & LIMITI
# ============================================================
TARGET_CASI_MINIMI = 1000
TARGET_PERC_MINIMA = 100.0
TARGET_COLPI_MAX = 16
MIN_NUMERI_GRUPPO = 5
MAX_NUMERI_GRUPPO = 5
MIN_SOGLIA = 6
MAX_SOGLIA = 9
POSSIBILI_SORTI_RICERCA = [1]
MIN_RUOTE_UNITE = 2
MAX_RUOTE_UNITE = 2
RUOTE_NOMI = ['BA','CA','FI','GE','MI','NA','PA','RO','TO','VE']
PATH_RUOTE = "/kaggle/input/estrazionilotto-aggiornate-al-20-1-2026"
SORTE_VERIFICA = 1
# ============================================================
# UTILITÀ
# ============================================================
def leggi_file_matrice(path):
if not os.path.exists(path):
print(f"⚠️ File non trovato: {path}")
return [GRUPPO_BASE_BACKUP]
matrice = []
try:
with open(path, 'r') as f:
for line in f:
line = line.strip()
if not line: continue
line_clean = re.sub(r'[^\d]+', ' ', line)
nums = [int(x) for x in line_clean.split() if x.isdigit()]
nums = sorted(list(set(nums)))
if len(nums) > 0:
matrice.append(nums)
except Exception as e:
print(f"⚠️ Errore lettura: {e}")
return [GRUPPO_BASE_BACKUP]
if not matrice: return [GRUPPO_BASE_BACKUP]
return matrice
def play_sound():
display(HTML("""<script>new Audio('https://www.soundjay.com/buttons/beep-01a.mp3').play();</script>"""))
def play_final_sound():
display(HTML("""
<script>
var a = new Audio('https://www.soundjay.com/buttons/beep-01a.mp3');
a.play(); setTimeout(function(){ a.play(); }, 500);
</script>
<b style="color:green; font-size:20px;">✅ ANALISI COMPLETATA!</b>
"""))
# ============================================================
# ENGINE
# ============================================================
def carica_bin():
estr = {}
min_len = 10**9
if not os.path.exists(PATH_RUOTE) and not os.path.exists(os.path.join(PATH_RUOTE, "estrazioni-BA.txt")):
min_len = 2000
binmat = np.zeros((min_len, len(RUOTE_NOMI), 90), dtype=np.uint8)
for t in range(min_len):
for r in range(len(RUOTE_NOMI)):
nums = np.random.choice(np.arange(90), 5, replace=False)
for n in nums: binmat[t, r, n] = 1
return binmat, min_len
for r in RUOTE_NOMI:
fname = os.path.join(PATH_RUOTE, f"estrazioni-{r}.txt")
if os.path.exists(fname):
rows = []
with open(fname) as f:
for l in f:
p = l.strip().split(".")
if len(p) == 5: rows.append([int(x) for x in p])
arr = np.array(rows, dtype=np.int16)
estr[r] = arr
min_len = min(min_len, len(arr))
for r in RUOTE_NOMI: estr[r] = estr[r][:min_len][::-1]
binmat = np.zeros((min_len, len(RUOTE_NOMI), 90), dtype=np.uint8)
for ri, r in enumerate(RUOTE_NOMI):
for t in range(min_len):
for n in estr[r][t]:
binmat[t, ri, n-1] = 1
return binmat, min_len
@njit(parallel=True)
def scan_core(binmat, combs, ruote_idx_list, sric, sver, thr_ric, thr_ver):
n_groups = ruote_idx_list.shape[0]
n_ruote_in_group = ruote_idx_list.shape[1]
ncomb = combs.shape[0]
nt = binmat.shape[0]
tot_ev = 0
tot_ok = 0
for g_idx in prange(n_groups):
for i in range(ncomb):
rit_ric = 0
in_ver = False
rit_ver = 0
for t in range(nt):
max_hit = 0
for r_sub_idx in range(n_ruote_in_group):
r_real = ruote_idx_list[g_idx, r_sub_idx]
current_hit = 0
for k in range(combs.shape[1]):
current_hit += binmat[t, r_real, combs[i,k]]
if current_hit > max_hit: max_hit = current_hit
if not in_ver:
if max_hit >= sric: rit_ric = 0
else: rit_ric += 1
if rit_ric >= thr_ric:
in_ver = True
rit_ver = 0
else:
rit_ver += 1
if max_hit >= sver:
tot_ev += 1
if rit_ver <= thr_ver: tot_ok += 1
in_ver = False
rit_ric = 0
return tot_ev, tot_ok
def valuta_stato(binmat, stato):
real_combs = np.array([ [x-1 for x in stato['gruppo']] ], dtype=np.int16)
n_r = stato['num_ruote']
ruote_combs = list(combinations(range(len(RUOTE_NOMI)), n_r))
ruote_idx_arr = np.array(ruote_combs, dtype=np.int32)
if ruote_idx_arr.ndim == 1:
ruote_idx_arr = ruote_idx_arr.reshape(-1, 1)
ev, ok = scan_core(
binmat, real_combs, ruote_idx_arr,
stato['sorte_ric'], SORTE_VERIFICA,
stato['soglia_ric'], TARGET_COLPI_MAX
)
perc = (ok / ev * 100) if ev > 0 else 0
return ev, ok, perc
@njit
def scan_dettagliata_single_group(binmat, combs, ruote_idx, sric, sver, thr_ric, thr_ver):
ncomb = combs.shape[0]
nt = binmat.shape[0]
n_ruote = ruote_idx.shape[0]
colpi_esito = np.zeros(5000, dtype=np.int16)
count_ev = 0
for i in range(ncomb):
rit_ric = 0
in_ver = False
rit_ver = 0
for t in range(nt):
max_hit = 0
for r_sub_idx in range(n_ruote):
r_real = ruote_idx[r_sub_idx]
current_hit = 0
for k in range(combs.shape[1]):
current_hit += binmat[t, r_real, combs[i,k]]
if current_hit > max_hit: max_hit = current_hit
if not in_ver:
if max_hit >= sric: rit_ric = 0
else: rit_ric += 1
if rit_ric >= thr_ric:
in_ver = True
rit_ver = 0
else:
rit_ver += 1
if max_hit >= sver:
if count_ev < 5000:
colpi_esito[count_ev] = rit_ver
count_ev += 1
in_ver = False
rit_ric = 0
return count_ev, colpi_esito
@njit
def check_active_status(binmat, combs, ruote_idx, sric, sver, thr_ric, thr_ver):
ncomb = combs.shape[0]
nt = binmat.shape[0]
n_ruote = ruote_idx.shape[0]
is_active = False
colpi_passati = 0
for i in range(ncomb):
rit_ric = 0
in_ver = False
rit_ver = 0
for t in range(nt):
max_hit = 0
for r_sub_idx in range(n_ruote):
r_real = ruote_idx[r_sub_idx]
current_hit = 0
for k in range(combs.shape[1]):
current_hit += binmat[t, r_real, combs[i,k]]
if current_hit > max_hit: max_hit = current_hit
if not in_ver:
if max_hit >= sric: rit_ric = 0
else: rit_ric += 1
if rit_ric >= thr_ric:
in_ver = True
rit_ver = 0
else:
rit_ver += 1
if max_hit >= sver:
in_ver = False
rit_ric = 0
if in_ver:
if rit_ver <= thr_ver:
is_active = True
colpi_passati = rit_ver
break
return is_active, colpi_passati
# ============================================================
# REPORTISTICA COMPLETA (PER OGNI RIGA)
# ============================================================
def stampa_report_completo_per_riga(binmat, stato, ev, perc, titolo="REPORT"):
SEP = "=" * 55
SUB = "-" * 40
print("\n" + SEP)
print(f" 🛑 {titolo}")
print(SEP)
print(f"📊 RISULTATO: {ev} Eventi Totali | {perc:.2f}% Positivi")
print(SUB)
print("⚙️ CONFIGURAZIONE:")
print(f" • Numeri nel Gruppo : {len(stato['gruppo'])}")
print(f" • Ruote Unite : {stato['num_ruote']}")
print(f" • Sorte Ricerca (Trig.) : {stato['sorte_ric']}")
print(f" • Soglia Ritardo : {stato['soglia_ric']}")
print(SUB)
print(f"🎱 LUNGHETTA TROVATA ({len(stato['gruppo'])}):")
print(f" {stato['gruppo']}")
print(SEP)
# 1. ANALISI BACKTEST DETTAGLIATA (OUTLIERS & MAX COLPO)
print(" 🔎 ANALISI BACKTEST (STORICO TOP 10)")
print(SUB)
real_combs = np.array([ [x-1 for x in stato['gruppo']] ], dtype=np.int16)
n_r = stato['num_ruote']
ruote_combs_list = list(combinations(range(len(RUOTE_NOMI)), n_r))
results = []
for rc in ruote_combs_list:
single_ruote_idx = np.array(rc, dtype=np.int32)
cnt, colpi_arr = scan_dettagliata_single_group(
binmat, real_combs, single_ruote_idx,
stato['sorte_ric'], SORTE_VERIFICA,
stato['soglia_ric'], TARGET_COLPI_MAX
)
if cnt > 0:
valid_colpi = colpi_arr[:cnt]
# Calcolo hit positivi per Max Colpo (IN TARGET)
hits = valid_colpi[valid_colpi <= TARGET_COLPI_MAX]
max_pos = np.max(hits) if len(hits) > 0 else 0
# Calcolo Max Colpo ASSOLUTO (incluso negativi)
max_abs = np.max(valid_colpi) if len(valid_colpi) > 0 else 0
ok = len(hits)
perc_loc = (ok / cnt) * 100
negativi = valid_colpi[valid_colpi > TARGET_COLPI_MAX]
dettagli_negativi = []
if len(negativi) > 0:
for n in negativi[:5]: dettagli_negativi.append(f"{n}")
if len(negativi) > 5: dettagli_negativi.append("..")
neg_str = ",".join(dettagli_negativi) if dettagli_negativi else "OK"
results.append({
"Ruote": "-".join([RUOTE_NOMI[x] for x in rc]),
"Ev": cnt,
"Perc": perc_loc,
"Out": neg_str,
"MaxPos": max_pos,
"MaxAbs": max_abs
})
df = pd.DataFrame(results)
if not df.empty:
df = df.sort_values(by=["Perc", "Ev"], ascending=False)
for idx, row in df.head(10).iterrows():
print(f"📌 {row['Ruote']} -> {row['Perc']:.2f}% ({row['Ev']} cs)")
print(f" ⏱️ Max In: {row['MaxPos']} | ⚠️ Max Abs: {row['MaxAbs']}")
if row['Perc'] < 100: print(f" ⚠️ Ritardatari: {row['Out']}")
else: print(f" ✅ PERFETTO")
print(SUB)
else:
print("Nessun evento trovato.")
# 2. PREVISIONI ATTIVE (TUTTE) PER QUESTA RIGA
print("\n 🔮 PREVISIONI ATTIVE (TUTTE)")
print(SUB)
found_any = False
for rc in ruote_combs_list:
single_ruote_idx = np.array(rc, dtype=np.int32)
active, colpi_passati = check_active_status(
binmat, real_combs, single_ruote_idx,
stato['sorte_ric'], SORTE_VERIFICA,
stato['soglia_ric'], TARGET_COLPI_MAX
)
if active:
found_any = True
colpi_rim = TARGET_COLPI_MAX - colpi_passati
nomi = "-".join([RUOTE_NOMI[x] for x in rc])
# Ricalcolo veloce statistiche
cnt, colpi_arr = scan_dettagliata_single_group(
binmat, real_combs, single_ruote_idx,
stato['sorte_ric'], SORTE_VERIFICA,
stato['soglia_ric'], TARGET_COLPI_MAX
)
perc_loc = 0
max_pos = 0
max_abs = 0
if cnt > 0:
valid = colpi_arr[:cnt]
hits = valid[valid <= TARGET_COLPI_MAX]
if len(hits) > 0: max_pos = np.max(hits)
max_abs = np.max(valid) if len(valid) > 0 else 0
perc_loc = (len(hits) / cnt) * 100
icon = "🟢" if perc_loc == 100 else "🟡"
print(f"{icon} {nomi}")
print(f" 🔥 Attiva da: {colpi_passati} | 🎲 Gioca per: {colpi_rim}")
print(f" 📊 Storico: {perc_loc:.1f}% | ⏱️ Max In: {max_pos} | ⚠️ Max Abs: {max_abs}")
print(SUB)
if not found_any: print("ℹ️ Nessuna previsione attiva per questa riga.")
print(SEP + "\n")
# ============================================================
# CRUSCOTTO FINALE (GRAND FINALE)
# ============================================================
def stampa_cruscotto_finale(binmat, risultati_globali):
if not risultati_globali: return
SEP = "=" * 70
print("\n\n")
print(SEP)
print(" 🚀 CRUSCOTTO FINALE DI SINTESI")
print(f" (Mostro SOLO previsioni urgenti con ≤ {SOGLIA_COLPI_RIMANENTI} colpi rimanenti)")
print(SEP)
previsioni_raccolte = []
# VARIABILI PER RECORD GLOBALI
global_max_in_target = 0
global_count_in = 0
global_max_absolute = 0
global_count_abs = 0
for nome_job, stato in risultati_globali:
real_combs = np.array([ [x-1 for x in stato['gruppo']] ], dtype=np.int16)
n_r = stato['num_ruote']
ruote_combs_list = list(combinations(range(len(RUOTE_NOMI)), n_r))
for rc in ruote_combs_list:
single_ruote_idx = np.array(rc, dtype=np.int32)
# Calcolo statistiche per aggiornare i RECORD GLOBALI
cnt, colpi_arr = scan_dettagliata_single_group(
binmat, real_combs, single_ruote_idx,
stato['sorte_ric'], SORTE_VERIFICA,
stato['soglia_ric'], TARGET_COLPI_MAX
)
if cnt > 0:
valid = colpi_arr[:cnt]
hits = valid[valid <= TARGET_COLPI_MAX]
# --- AGGIORNAMENTO MAX IN TARGET ---
if len(hits) > 0:
local_max_in = np.max(hits)
local_count_in = np.sum(hits == local_max_in)
if local_max_in > global_max_in_target:
global_max_in_target = local_max_in
global_count_in = local_count_in
elif local_max_in == global_max_in_target:
global_count_in += local_count_in
# --- AGGIORNAMENTO MAX ABSOLUTE ---
if len(valid) > 0:
local_max_abs = np.max(valid)
local_count_abs = np.sum(valid == local_max_abs)
if local_max_abs > global_max_absolute:
global_max_absolute = local_max_abs
global_count_abs = local_count_abs
elif local_max_abs == global_max_absolute:
global_count_abs += local_count_abs
# Check stato attivo per la lista
active, colpi_passati = check_active_status(
binmat, real_combs, single_ruote_idx,
stato['sorte_ric'], SORTE_VERIFICA,
stato['soglia_ric'], TARGET_COLPI_MAX
)
if active:
colpi_rim = TARGET_COLPI_MAX - colpi_passati
if colpi_rim <= SOGLIA_COLPI_RIMANENTI:
perc_loc = 0
local_max_pos = 0
local_max_abs = 0
if cnt > 0:
valid = colpi_arr[:cnt]
hits = valid[valid <= TARGET_COLPI_MAX]
if len(hits) > 0: local_max_pos = np.max(hits)
if len(valid) > 0: local_max_abs = np.max(valid)
perc_loc = (len(hits) / cnt) * 100
previsioni_raccolte.append({
'ID': nome_job,
'Ruote': "-".join([RUOTE_NOMI[x] for x in rc]),
'Numeri': str(stato['gruppo']),
'Passati': colpi_passati,
'Rimasti': colpi_rim,
'Storico': perc_loc,
'Casi': cnt,
'MaxPos': local_max_pos,
'MaxAbs': local_max_abs
})
if not previsioni_raccolte:
print("ℹ️ Nessuna previsione soddisfa i criteri di alta urgenza.")
else:
# 1. STAMPA CLASSIFICA STANDARD
df = pd.DataFrame(previsioni_raccolte)
df = df.sort_values(by=['Rimasti', 'Storico'], ascending=[True, False])
for idx, row in df.iterrows():
icona = "🔴" if row['Rimasti'] <= 1 else "⚡"
print(f"{icona} [{row['ID']}] {row['Ruote']} -> {row['Numeri']}")
print(f" ⏳ RIMANGONO: {row['Rimasti']} colpi (Attiva da {row['Passati']})")
print(f" 📊 Affidabilità: {row['Storico']:.1f}% su {row['Casi']} casi")
print(f" ⏱️ Max In: {row['MaxPos']} | ⚠️ Max Abs: {row['MaxAbs']}")
print("-" * 70)
print(SEP)
# 2. RIEPILOGO CONVERGENZE
print("\n\n")
print("=" * 70)
print(" 🧩 RIEPILOGO CONVERGENZE (Ruote Unite)")
print(" (Uniscono ruote con stessi numeri e colpi teorici se hanno intersezioni)")
print("=" * 70)
groups = {}
for p in previsioni_raccolte:
key = (p['Numeri'], p['Rimasti'])
ruote_set = set(p['Ruote'].split('-'))
if key not in groups:
groups[key] = []
groups[key].append(ruote_set)
any_agg_found = False
sorted_keys = sorted(groups.keys(), key=lambda x: x[1])
for k in sorted_keys:
nums_str, rimasti = k
sets_list = groups[k]
if len(sets_list) < 2: continue
clusters = []
for s in sets_list:
candidates_idx = []
for i, c in enumerate(clusters):
if not s.isdisjoint(c['ruote']):
candidates_idx.append(i)
if not candidates_idx:
clusters.append({'ruote': s, 'count': 1})
else:
base_idx = candidates_idx[0]
clusters[base_idx]['ruote'].update(s)
clusters[base_idx]['count'] += 1
for other_idx in sorted(candidates_idx[1:], reverse=True):
clusters[base_idx]['ruote'].update(clusters[other_idx]['ruote'])
clusters[base_idx]['count'] += clusters[other_idx]['count']
clusters.pop(other_idx)
all_ruote_ordered = ['BA','CA','FI','GE','MI','NA','PA','RO','TO','VE']
for c in clusters:
if c['count'] >= 2:
any_agg_found = True
rr = sorted(list(c['ruote']), key=lambda x: all_ruote_ordered.index(x) if x in all_ruote_ordered else 99)
ruote_str_compact = "".join(rr)
print(f"🔗 {ruote_str_compact} {nums_str} -> ⏳ {rimasti} colpi teorici")
print("-" * 70)
if not any_agg_found:
print("ℹ️ Nessuna convergenza complessa trovata.")
# 3. RECORD GLOBALI (AGGIUNTA v30)
print("\n\n")
print("=" * 70)
print(" 🏆 RECORD STORICI DELL'INTERA RICERCA (Tra tutti i casi esaminati)")
print("=" * 70)
print(f" • ⏱️ Max Ritardo (In Target) : {global_max_in_target} (verificato {global_count_in} volte)")
print(f" • ⚠️ Max Ritardo Assoluto : {global_max_absolute} (verificato {global_count_abs} volte)")
print("=" * 70)
# ============================================================
# OPTIMIZATION FUNCTION
# ============================================================
def run_optimization_for_pool(binmat, pool_numeri, id_riga_display):
SEP = "=" * 55
print("\n" + SEP)
print(f" ⚡ AVVIO ANALISI: {id_riga_display}")
print(f" 🎱 Numeri: {pool_numeri}")
print(SEP)
start_size = random.randint(MIN_NUMERI_GRUPPO, MAX_NUMERI_GRUPPO)
if len(pool_numeri) < start_size: start_size = len(pool_numeri)
current_stato = {
'gruppo': sorted(random.sample(pool_numeri, start_size)),
'soglia_ric': random.randint(MIN_SOGLIA, MAX_SOGLIA),
'sorte_ric': random.choice(POSSIBILI_SORTI_RICERCA),
'num_ruote': random.randint(MIN_RUOTE_UNITE, MAX_RUOTE_UNITE)
}
cur_ev, cur_ok, cur_perc = valuta_stato(binmat, current_stato)
best_stato = copy.deepcopy(current_stato)
best_ev, best_ok, best_perc = cur_ev, cur_ok, cur_perc
# tqdm con dynamic_ncols e POSTFIX dinamico
pbar = tqdm(desc=f"Opt {id_riga_display}", unit="it", dynamic_ncols=True)
stagnation_zero = 0
start_time = time.time()
timeout_seconds = TIMEOUT_MINUTI_PER_RIGA * 60
try:
while True:
if time.time() - start_time > timeout_seconds:
pbar.close()
stampa_report_completo_per_riga(binmat, best_stato, best_ev, best_perc, f"TIMEOUT {id_riga_display}")
return best_stato
if best_ev >= TARGET_CASI_MINIMI and best_perc >= TARGET_PERC_MINIMA:
pbar.close()
play_sound()
stampa_report_completo_per_riga(binmat, best_stato, best_ev, best_perc, f"VITTORIA {id_riga_display}")
return best_stato
pbar.update(1)
pbar.set_description(f"Best: {best_perc:.1f}% ({best_ev})")
# Update POSTFIX dinamico
pbar.set_postfix(
L=len(new_stato['gruppo'] if 'new_stato' in locals() else current_stato['gruppo']),
R=current_stato['num_ruote'],
Sg=current_stato['soglia_ric'],
LastEv=cur_ev
)
if best_ev == 0:
stagnation_zero += 1
if stagnation_zero > 50:
current_stato['soglia_ric'] = random.randint(MIN_SOGLIA, MAX_SOGLIA)
stagnation_zero = 0
new_stato = copy.deepcopy(current_stato)
dice = random.random()
if dice < 0.25:
r2 = random.random()
if r2 < 0.33:
new_stato['soglia_ric'] += random.choice([-10, -5, 5, 10])
new_stato['soglia_ric'] = max(MIN_SOGLIA, min(MAX_SOGLIA, new_stato['soglia_ric']))
elif r2 < 0.66:
new_stato['num_ruote'] += random.choice([-1, 1])
new_stato['num_ruote'] = max(MIN_RUOTE_UNITE, min(MAX_RUOTE_UNITE, new_stato['num_ruote']))
else:
new_stato['sorte_ric'] = random.choice(POSSIBILI_SORTI_RICERCA)
elif dice < 0.45:
curr_len = len(new_stato['gruppo'])
action = 0
if curr_len < MAX_NUMERI_GRUPPO and curr_len > MIN_NUMERI_GRUPPO: action = random.choice([-1, 1])
elif curr_len == MIN_NUMERI_GRUPPO and curr_len < MAX_NUMERI_GRUPPO: action = 1
elif curr_len == MAX_NUMERI_GRUPPO and curr_len > MIN_NUMERI_GRUPPO: action = -1
if action == 1:
pool = [x for x in pool_numeri if x not in new_stato['gruppo']]
if pool:
new_stato['gruppo'].append(random.choice(pool))
new_stato['gruppo'].sort()
elif action == -1:
new_stato['gruppo'].pop(random.randint(0, len(new_stato['gruppo'])-1))
else:
n_chg = 1
if cur_ev < TARGET_CASI_MINIMI / 2: n_chg = 2
for _ in range(n_chg):
if len(new_stato['gruppo']) > 0: new_stato['gruppo'].pop(random.randint(0, len(new_stato['gruppo'])-1))
pool = [n for n in pool_numeri if n not in new_stato['gruppo']]
while len(new_stato['gruppo']) < len(current_stato['gruppo']):
if not pool: break
r = random.choice(pool)
new_stato['gruppo'].append(r)
pool.remove(r)
new_stato['gruppo'].sort()
ev, ok, perc = valuta_stato(binmat, new_stato)
accepted = False
if ev > 0:
if perc > best_perc: accepted = True
elif perc == best_perc and ev > best_ev: accepted = True
elif random.random() < 0.05: accepted = True
if accepted:
current_stato = new_stato
if perc > best_perc or (perc == best_perc and ev > best_ev):
best_stato = copy.deepcopy(new_stato)
best_ev, best_ok, best_perc = ev, ok, perc
tqdm.write(f"★ {ev} ({perc:.1f}%) | L:{len(new_stato['gruppo'])} R{new_stato['num_ruote']} Sg{new_stato['soglia_ric']}")
cur_ev = ev
except KeyboardInterrupt:
pbar.close()
print(f"⚠️ STOP MANUALE SU {id_riga_display}")
stampa_report_completo_per_riga(binmat, best_stato, best_ev, best_perc, f"INTERROTTO {id_riga_display}")
return best_stato
# ============================================================
# MAIN
# ============================================================
def main_autonomous():
binmat, num_estr = carica_bin()
print("\n" + "="*60)
print(" 🤖 BOT INTELLIGENTE v32 - SAFETY INPUT MODE")
print("="*60)
# 1. INFO DATI
print("📂 DATI ESTRAZIONI:")
print(f" • Database: {PATH_RUOTE}")
print(f" • Estrazioni caricate: {num_estr}")
print("-" * 60)
# SELEZIONE BLINDATA DELLA MODALITÀ
modalita_effettiva = 'FILE'
if TIPO_INPUT.strip().upper() == 'MANUALE':
modalita_effettiva = 'MANUALE'
# 2. INFO INPUT
print("📊 INPUT MATRICE:")
if modalita_effettiva == 'FILE':
print(f" • Modalità: FILE")
print(f" • Path: {PATH_FILE_MATRICE}")
else:
print(f" • Modalità: LISTA MANUALE (Hard-Coded)")
print(f" • Righe caricate: {len(MATRICE_MANUALE)}")
print(f" • Strategia Riga: {RIGA_DA_ANALIZZARE} ", end="")
if RIGA_DA_ANALIZZARE == -2: print("(Batch Sequenziale)")
elif RIGA_DA_ANALIZZARE == -1: print("(Merge Totale)")
else: print("(Riga Singola)")
print("-" * 60)
# 3. PARAMETRI
print("⚙️ PARAMETRI DI RICERCA:")
print(f" • Lunghezza Gruppo: {MIN_NUMERI_GRUPPO} - {MAX_NUMERI_GRUPPO}")
print(f" • Ruote Unite: {MIN_RUOTE_UNITE} - {MAX_RUOTE_UNITE}")
print(f" • Range Ritardo: {MIN_SOGLIA} - {MAX_SOGLIA}")
print(f" • Sorte di Ricerca : {POSSIBILI_SORTI_RICERCA}")
print(f" • Sorte di Verifica : {SORTE_VERIFICA}")
print(f" • Colpi di Verifica : {TARGET_COLPI_MAX}")
print(f" • Timeout per Riga: {TIMEOUT_MINUTI_PER_RIGA} minuti")
print("-" * 60)
# 4. OBIETTIVI
print("🏆 OBIETTIVI & OUTPUT:")
print(f" • Target Minimo: >{TARGET_CASI_MINIMI} Eventi | {TARGET_PERC_MINIMA}% Ok")
print(f" • Filtro Finale: Mostra solo previsioni con ≤ {SOGLIA_COLPI_RIMANENTI} colpi.")
print("="*60 + "\n")
# CARICAMENTO DATI
matrice_completa = []
if modalita_effettiva == 'FILE':
matrice_completa = leggi_file_matrice(PATH_FILE_MATRICE)
else:
matrice_completa = MATRICE_MANUALE
# Assicuriamoci che siano liste di interi e ordinate
cleaned = []
for row in matrice_completa:
if isinstance(row, list):
cleaned.append(sorted(list(set(row))))
matrice_completa = cleaned
if not matrice_completa:
print("⚠️ ERRORE: Nessun dato trovato in input (o lista manuale vuota). Uso gruppo backup.")
matrice_completa = [GRUPPO_BASE_BACKUP]
pools_da_analizzare = []
if RIGA_DA_ANALIZZARE == -1:
pool_totale = set()
for r in matrice_completa: pool_totale.update(r)
pools_da_analizzare.append(("ALL_MERGED", sorted(list(pool_totale))))
elif RIGA_DA_ANALIZZARE == -2:
for i, r in enumerate(matrice_completa): pools_da_analizzare.append((f"RIGA_{i}", r))
elif 0 <= RIGA_DA_ANALIZZARE < len(matrice_completa):
pools_da_analizzare.append((f"RIGA_{RIGA_DA_ANALIZZARE}", matrice_completa[RIGA_DA_ANALIZZARE]))
else:
pools_da_analizzare.append(("RIGA_0", matrice_completa[0]))
risultati_globali = []
try:
for nome_job, pool in pools_da_analizzare:
best_state = run_optimization_for_pool(binmat, pool, nome_job)
if best_state:
risultati_globali.append((nome_job, best_state))
time.sleep(1)
play_final_sound()
stampa_cruscotto_finale(binmat, risultati_globali)
except KeyboardInterrupt:
print("\n🛑 INTERRUZIONE. Genero report riassuntivo del lavoro svolto...")
stampa_cruscotto_finale(binmat, risultati_globali)
if __name__ == "__main__":
main_autonomous()
Buon divertimento... pythoniani e klagghiani e hugginfaciani in ascolto...
ps: ovviamente come tutti i prg e sw (sopratutto quelli vibe codati) potrebbe avere bugs e problemi operativi ma il bello... credo stia anche nello scovarli insieme e cercare di risolvere anche quelli...
nb: il dataset archivio estrazioni deve essere nella forma : estrazioni-BA.txt ecc... fino a estrazioni-NZ.txt contenenti le estrazioni in formato numerico a doppia cifra con lo 0 davanti per i numeri da 1 a 9 , con cinque numeri intervallati da carattere punto e con le estrazioni recenti in alto e quelle vecchie in basso.
Ultima modifica: