Compare commits

..
1 Commits
Author SHA1 Message Date
cbazzaandClaude Sonnet 5 c9da3841f9 Add regression tests for the popularity/EV score
Ports tests/test_popularity_score.py from the Lotto sibling project
(same purpose: pin down known overplayed combinations scoring lower
than spread ones), adapted for 5 main numbers and adds coverage for
the Euro-number determinism bug fixed in 0285a1c (tips #1-3 used to
always return the identical pair). Also documents beautifulsoup4 as
a required dependency in the README, which was missing despite
update_from_eurojackpot_zahlen_eu.py needing it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-09-12 10:08:59 +02:00
3 changed files with 96 additions and 1 deletions

No files matched your search

+10 -1
View File
@@ -57,7 +57,7 @@ Eurojackpot/
```bash ```bash
python3 -m venv venv python3 -m venv venv
source venv/bin/activate source venv/bin/activate
pip install pandas numpy scikit-learn requests torch pip install pandas numpy scikit-learn requests torch beautifulsoup4
``` ```
### 2. Telegram-Bot einrichten ### 2. Telegram-Bot einrichten
@@ -139,6 +139,15 @@ Tipp, Ø Confidence/Quality, Trefferauswertung).
Alle Generierungen werden in `data/generated_tips/generation_history.json` Alle Generierungen werden in `data/generated_tips/generation_history.json`
protokolliert, alle Ziehungsauswertungen in `data/learning_log.json`. protokolliert, alle Ziehungsauswertungen in `data/learning_log.json`.
## 🧪 Tests
Regressionstests für den Popularity/EV-Score (`tests/test_popularity_score.py`):
```bash
pip install pytest
pytest tests/
```
## 🗂️ Datenformat ## 🗂️ Datenformat
`data/AlleEurojackpotzahlen.csv` (Semikolon-getrennt): `data/AlleEurojackpotzahlen.csv` (Semikolon-getrennt):
+7
View File
@@ -159,3 +159,10 @@ Navigierbare Graph-Ansicht unter `graphify-out/`:
Bei strukturellen Änderungen: `/graphify --update` zum inkrementellen Bei strukturellen Änderungen: `/graphify --update` zum inkrementellen
Neuaufbau. Neuaufbau.
## 7. Tests
`tests/test_popularity_score.py` (pytest) prüft den Popularity/EV-Score
gegen bekannte Vielspieler-Kombinationen (portiert von Lotto) und deckt
außerdem den Euro-Zahlen-Determinismus-Bug ab (Tipps #1-3 lieferten früher
immer dasselbe Paar). Ausführen mit `pytest tests/`.
+79
View File
@@ -0,0 +1,79 @@
"""
Regressionstests für den Popularity/EV-Score.
Port der Lotto-Tests (siehe dortiges tests/test_popularity_score.py), an das
Eurojackpot-Format angepasst: 5 Hauptzahlen statt 6, Split-Mittelpunkt 2.5
statt 3. Stellt sicher, dass bekannte Vielspieler-Kombinationen konsistent
NIEDRIGER bewertet werden als gestreute - genau das hatte der beim
Lotto-Projekt gefundene Sum-Extremity-Bug (Commit e05f1f1 dort) verletzt,
bevor der Fix hierher portiert wurde.
"""
import os
import sys
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "scripts", "generators"))
from ultimate_ai_ml_eurojackpot_generator import UltimateAIMLEurojackpotGenerator as Generator
OVERPLAYED_COMBOS = [
[1, 2, 3, 4, 5],
[5, 10, 15, 20, 25],
]
SPREAD_COMBOS = [
[5, 26, 28, 30, 40], # echte Ziehung vom 14.08.2026
[2, 17, 29, 33, 48],
]
def test_overplayed_combos_score_low():
for combo in OVERPLAYED_COMBOS:
score = Generator._calculate_popularity_score(combo)
assert score < 0.3, f"{combo} sollte als populär (niedriger Score) gelten, war {score:.3f}"
def test_spread_combos_score_high():
for combo in SPREAD_COMBOS:
score = Generator._calculate_popularity_score(combo)
assert score > 0.5, f"{combo} sollte als unpopulär (hoher Score) gelten, war {score:.3f}"
def test_overplayed_never_outscores_spread():
"""Regressionsschutz für den (portierten) Sum-Extremity-Bug: eine
bekannte Vielspieler-Kombination darf NIE höher bewerten als eine
gestreute."""
worst_overplayed = max(Generator._calculate_popularity_score(c) for c in OVERPLAYED_COMBOS)
best_spread = min(Generator._calculate_popularity_score(c) for c in SPREAD_COMBOS)
assert worst_overplayed < best_spread
def test_arithmetic_progression_penalized_regardless_of_step():
step_one = Generator._calculate_popularity_score([10, 11, 12, 13, 14])
step_seven = Generator._calculate_popularity_score([2, 9, 16, 23, 30])
spread = Generator._calculate_popularity_score([2, 14, 23, 31, 40])
assert step_one < spread
assert step_seven < spread
def test_balanced_odd_even_split_scores_lower_than_extreme_split():
"""Bei 5 Zahlen ist 2-3/3-2 der ausgeglichenste Split (Mittelpunkt 2.5) -
ein extremer Split (hier 5 gerade) sollte höher bewerten."""
balanced = Generator._calculate_popularity_score([2, 3, 34, 35, 46]) # 2 gerade, 3 ungerade
extreme = Generator._calculate_popularity_score([2, 4, 34, 36, 46]) # 5 gerade
assert extreme > balanced
def test_score_bounded_between_zero_and_one():
for combo in OVERPLAYED_COMBOS + SPREAD_COMBOS:
score = Generator._calculate_popularity_score(combo)
assert 0.0 <= score <= 1.0
def test_euro_numbers_not_deterministic_across_first_three_tips():
"""Regressionsschutz für den Bug, bei dem Tipps #1-3 IMMER exakt
dasselbe Euro-Zahlenpaar bekamen (starre Top-2-AI-Prediction ohne
Zufall) - siehe Commit 0285a1c."""
gen = Generator.__new__(Generator) # Instanz ohne teuren __init__
euro_preds = {n: 0.3 for n in range(1, 13)}
pairs = [tuple(gen._get_smart_euro_numbers(tip, euro_preds)) for tip in (1, 2, 3)]
assert len(set(pairs)) > 1, f"Tipps 1-3 lieferten alle dasselbe Euro-Paar: {pairs}"