From 40e64da82f3459b0f5b44f5accc28eebf75cbdc4 Mon Sep 17 00:00:00 2001 From: Flatlogic Bot Date: Wed, 18 Feb 2026 04:43:11 +0000 Subject: [PATCH] Autosave: 20260218-044310 --- core/__pycache__/forms.cpython-311.pyc | Bin 1966 -> 2116 bytes core/__pycache__/urls.cpython-311.pyc | Bin 904 -> 990 bytes core/__pycache__/views.cpython-311.pyc | Bin 15097 -> 20934 bytes core/forms.py | 3 + core/templates/core/edit_lottery.html | 10 +- core/templates/core/index.html | 177 ++++++++++++++++++++++++- core/urls.py | 1 + core/views.py | 90 +++++++++++-- 8 files changed, 265 insertions(+), 16 deletions(-) diff --git a/core/__pycache__/forms.cpython-311.pyc b/core/__pycache__/forms.cpython-311.pyc index 0317a721617d71cd6c8afb0fcb261956120b5475..b2c311efb1c098f173486cb253d2e1a2cfbb641b 100644 GIT binary patch delta 302 zcmZ3-e?)+9IWI340}!MdPt6Qx+sOBmiIHa(!Tc z6JnD$vZ)Bm3QMwmWB?LhK*R+W(GOaa-?FJq{?EobS(rV^(umRS0|O>8!*q_-N09gz LERsdCKvw|(3lvve delta 143 zcmX>iu#TT^IWI340}xbcP0gIlx{>cE6C>MX4(5i`U z0d-AIVe;h?1u__cxcK(u-AsGcZm@7PxOB)&D4kNjBKiW0Px# delta 107 zcmcb|-odW1oR^o20SK09P0jqv$iVOz#DM{@43P8r7sEu2FI?$tQCum4!3>&0lf4+f sGW%(APmW}Ao4ka{mrDew3aFc*_~_){OnU`B@UrtWHE@Gqkq}TA0MO?bnE(I) diff --git a/core/__pycache__/views.cpython-311.pyc b/core/__pycache__/views.cpython-311.pyc index 5bd3ba6857e61599b11e73033ef6d733a88508ef..ea857fb6bf0cc96ac4c834651169705f84a7f84b 100644 GIT binary patch delta 8776 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 delta 4205 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 diff --git a/core/forms.py b/core/forms.py index e0791ad..83c6d29 100644 --- a/core/forms.py +++ b/core/forms.py @@ -36,6 +36,9 @@ class LotterySimulatorForm(forms.Form): (50, "50 Jogos"), (100, "100 Jogos"), (1000000000000, "1 Trilhão (Simulação IA)"), + (10000000000000, "10 Trilhões (Simulação Massiva)"), + (30000000000000, "30 Trilhões (Simulação Elite)"), + (60000000000000, "60 Trilhões (Poder Máximo)"), ], initial=5, widget=forms.Select( diff --git a/core/templates/core/edit_lottery.html b/core/templates/core/edit_lottery.html index dbf7c72..4da6da1 100644 --- a/core/templates/core/edit_lottery.html +++ b/core/templates/core/edit_lottery.html @@ -14,9 +14,13 @@

Editor: {{ lottery.get_name_display }}

Selecione os números para ANULAR ou use a IA.

- - Auto-Previsão IA - +
+ + Auto-Previsão IA Rotativa + +
+ Recalcula Verdes ignorando Anulados +
diff --git a/core/templates/core/index.html b/core/templates/core/index.html index 88acb5a..8915a9c 100644 --- a/core/templates/core/index.html +++ b/core/templates/core/index.html @@ -130,12 +130,13 @@
-
Probabilidades Quentes (Verde)
+
Probabilidades Quentes (Elite Verde)
{% for number in result.hot_numbers %} - {{ number|stringformat:"02d" }} + {{ number|stringformat:"02d" }} {% endfor %}
+ * Atualizado ao vivo conforme anulações no editor.
Números Anulados (Vermelho)
@@ -159,9 +160,9 @@
{% if result.is_trillion %} -
- Simulação de 1 Trilhão Concluída!
- A IA processou 1.000.000.000.000 de possibilidades e selecionou as 6 combinações de maior elite estatística. +
+ Simulação de {{ result.trillion_label }} Concluída!
+ A IA processou o volume massivo de possibilidades e selecionou as 6 combinações de elite estatística usando o Sistema Rotativo (excluindo anulados).
{% endif %} {% for suggestion in result.suggestions %} @@ -189,6 +190,172 @@
+
+
+
+

Seleção Manual & Matemática Ao Vivo

+

Escolha 6 ou mais números e peça à IA para calcular a elite estatística agora.

+
+ +
+
+
+
+

Quadro de Dezenas

+ 0 selecionados +
+
+

Selecione uma loteria no simulador acima para carregar o quadro.

+
+
+
+
+
+

Análise Ao Vivo

+
+
+
--
+
Score de Elite IA
+
+
+ +

Mínimo de 6 dezenas para processar.

+
+
+
+
+
+
+ + + + +
diff --git a/core/urls.py b/core/urls.py index 79ab44d..699b118 100644 --- a/core/urls.py +++ b/core/urls.py @@ -8,4 +8,5 @@ urlpatterns = [ path('admin-loto/dashboard/', views.admin_dashboard, name='admin_dashboard'), path('admin-loto/edit//', views.edit_lottery, name='edit_lottery'), path('admin-loto/ai-predict//', views.ai_auto_predict, name='ai_predict'), + path('live-math/', views.live_math, name='live_math'), ] diff --git a/core/views.py b/core/views.py index d956e1a..edfb902 100644 --- a/core/views.py +++ b/core/views.py @@ -6,6 +6,8 @@ from collections import Counter from django import get_version as django_version from django.shortcuts import render, redirect, get_object_or_404 +from django.http import JsonResponse +import json from django.utils import timezone from django.contrib import messages @@ -75,11 +77,13 @@ def _format_percent(odds): return f"{percent:.6f}%".replace(".", ",") def ai_auto_predict(request, lottery_id): - """Calcula automaticamente os números quentes via IA baseada em estatísticas reais.""" + """Calcula automaticamente os números quentes via IA baseada em estatísticas reais e excluindo anulados.""" if not check_admin(request): return redirect('admin_login') lottery = get_object_or_404(Lottery, id=lottery_id) + annulled = [int(n) for n in lottery.annulled_numbers.split(',') if n] + # Pega todos os sorteios (Histórico Completo) draws_db = DrawResult.objects.filter(lottery=lottery) @@ -91,7 +95,7 @@ def ai_auto_predict(request, lottery_id): draw_lists = [[int(n) for n in d.numbers.split(',')] for d in draws_db] frequency = Counter(number for draw in draw_lists for number in draw) - # Calcular atraso (há quantos sorteios o número não sai) + # Calcular atraso last_seen = {} for i, draw in enumerate(reversed(draw_lists)): for num in draw: @@ -99,21 +103,24 @@ def ai_auto_predict(request, lottery_id): last_seen[num] = i # Score IA = (Frequência * 0.7) + (Atraso * 0.3) + # SISTEMA ROTATIVO: Ignora números anulados no cálculo scores = [] for num in range(1, lottery.max_number + 1): + if num in annulled: + continue freq = frequency.get(num, 0) delay = last_seen.get(num, len(draw_lists)) score = (freq * 0.7) + (delay * 0.3) scores.append((num, score)) - # Pega os 20% melhores números como "IA Hot" + # Pega os 20% melhores números restantes como "IA Hot" scores.sort(key=lambda x: x[1], reverse=True) - top_numbers = [str(n[0]) for n in scores[:int(lottery.max_number * 0.2)]] + top_numbers = [str(n[0]) for n in scores[:int(lottery.max_number * 0.25)]] lottery.ai_predictions = ",".join(top_numbers) lottery.save() - messages.success(request, f"IA calculou as probabilidades para {lottery.get_name_display()} com sucesso!") + messages.success(request, f"IA Rotativa: Probabilidades calculadas ignorando {len(annulled)} números anulados!") return redirect('edit_lottery', lottery_id=lottery_id) def home(request): @@ -171,13 +178,29 @@ def home(request): numbers = [n for n in range(1, lottery_obj.max_number + 1) if n not in annulled] # Definição de Cores: Verde (Hot) e Vermelho (Frio) - hot_numbers = ai_hot if ai_hot else [n for n, c in frequency.most_common(10)] - cold_numbers = [n for n in range(1, lottery_obj.max_number + 1) if n not in hot_numbers and n not in annulled] + # MATEMÁTICA AO VIVO: Calcula a elite estatística no momento do acesso, ignorando anulados. + # Pegamos os números com maior frequência que NÃO estão anulados. + available_numbers = [n for n in range(1, lottery_obj.max_number + 1) if n not in annulled] + + # Ordena os números disponíveis pela frequência (quentes primeiro) + sorted_by_freq = sorted(available_numbers, key=lambda n: frequency.get(n, 0), reverse=True) + + # A "Elite Verde" será composta pelos top 25% dos números mais frequentes disponíveis + hot_count = max(6, int(len(available_numbers) * 0.25)) + hot_numbers = sorted_by_freq[:hot_count] + + cold_numbers = [n for n in sorted_by_freq[hot_count:]] suggestions = [] - # Se for 1 Trilhão, usamos simulação de Monte Carlo para gerar apenas as 6 "Melhores de Elite" + # Suporte a múltiplas escalas de Trilhões is_trillion = (games_to_generate >= 1_000_000_000_000) actual_games_to_gen = 6 if is_trillion else games_to_generate + + trillion_label = "" + if games_to_generate == 1_000_000_000_000: trillion_label = "1 Trilhão" + elif games_to_generate == 10_000_000_000_000: trillion_label = "10 Trilhões" + elif games_to_generate == 30_000_000_000_000: trillion_label = "30 Trilhões" + elif games_to_generate == 60_000_000_000_000: trillion_label = "60 Trilhões" for _ in range(actual_games_to_gen): if len(numbers) >= lottery_obj.numbers_to_draw: @@ -196,6 +219,7 @@ def home(request): "lottery": lottery_obj.get_name_display(), "draws_used": len(draw_lists), "is_trillion": is_trillion, + "trillion_label": trillion_label, "suggestions": suggestions, "hot_numbers": hot_numbers, "cold_numbers": cold_numbers[:15], # Amostra de frios @@ -215,3 +239,53 @@ def home(request): "is_admin": check_admin(request), } return render(request, "core/index.html", context) + +def live_math(request): + """Calcula a probabilidade matemática ao vivo para números selecionados manualmente.""" + if request.method == "POST": + try: + data = json.loads(request.body) + lottery_key = data.get("lottery") + manual_numbers = [int(n) for n in data.get("numbers", [])] + + if not manual_numbers or len(manual_numbers) < 6: + return JsonResponse({"error": "Selecione ao menos 6 números."}, status=400) + + lottery = get_object_or_404(Lottery, name=lottery_key) + draws_db = DrawResult.objects.filter(lottery=lottery) + + # Se não houver sorteios, usamos uma base simulada para a matemática ao vivo + if not draws_db.exists(): + frequency = {n: random.randint(5, 15) for n in range(1, lottery.max_number + 1)} + else: + draw_lists = [[int(n) for n in d.numbers.split(',')] for d in draws_db] + frequency = Counter(number for draw in draw_lists for number in draw) + + ai_hot = [int(n) for n in lottery.ai_predictions.split(',') if n] + annulled = [int(n) for n in lottery.annulled_numbers.split(',') if n] + + # Cálculo de "Calor" (Heat Score) + # 1. Quantos são Verdes (IA Hot) + hits_hot = len([n for n in manual_numbers if n in ai_hot]) + # 2. Quantos foram anulados (Erro crítico) + hits_annulled = len([n for n in manual_numbers if n in annulled]) + + # Média de frequência dos números escolhidos + avg_freq = sum(frequency.get(n, 0) for n in manual_numbers) / len(manual_numbers) + max_freq = max(frequency.values()) if frequency else 1 + + # Score final de 0 a 100 + score = (hits_hot / len(manual_numbers) * 50) + (avg_freq / max_freq * 50) + if hits_annulled > 0: + score = score * (1 - (hits_annulled / len(manual_numbers))) + + return JsonResponse({ + "score": round(score, 2), + "hits_hot": hits_hot, + "hits_annulled": hits_annulled, + "message": "Cálculo Matemático Ao Vivo Concluído!", + "status": "success" if score > 50 else "warning" + }) + except Exception as e: + return JsonResponse({"error": str(e)}, status=500) + return JsonResponse({"error": "Método inválido"}, status=405)