Ground popularity/EV score in empirical player-choice biases
Ports the fix already applied to the sibling Lotto 6aus49 project. Since draws are i.i.d., only expected value (jackpot-sharing avoidance) is improvable, not hit probability. Replaces the ad-hoc "lucky numbers" list with empirically-documented picks, adds general arithmetic-progression detection (not just +1 consecutive pairs), and scores extreme odd/even splits higher (adjusted for 5 main numbers: distance from the 2.5 midpoint, not 3 as in the 6-number Lotto case). Deliberately omits a sum-near-mean component - testing against known overplayed combinations (1-2-3-4-5, 5-10-15-20-25) during the Lotto port showed it inverted the ranking for tightly clustered sequences. Raises popularity's weight in the quality score from 20% to 45% (main/euro/pattern/recency reduced accordingly), since those signals carry no real predictive value for hit probability. Also fixes _get_smart_euro_numbers(), which previously returned the literal same Euro-number pair for tips #1-3 every single run (top-2 AI predictions, no randomization) and had zero EV consideration. Now weighted-random across all 12 candidates with lucky numbers (3, 7) downweighted - deliberately more conservative than the main-number heuristic since 1-12 overlaps with calendar months and has no clear birthday-range split to exploit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -93,6 +93,11 @@ class UltimateAIMLEurojackpotGenerator:
|
|||||||
Ultimate Eurojackpot Generator - ALLE Strategien kombiniert
|
Ultimate Eurojackpot Generator - ALLE Strategien kombiniert
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
# Empirisch belegte "griffige" Einzelzahlen, die Spieler überproportional oft frei
|
||||||
|
# wählen (Quelle: Analysen realer Tippscheine, z.B. frz. 6aus49 über 25 Jahre:
|
||||||
|
# populärste Zahlen 5,7,9,11,12,13). Unabhängig vom Geburtstags-Bias (<=31).
|
||||||
|
POPULAR_PLAYER_PICKS = {5, 7, 9, 11, 12, 13}
|
||||||
|
|
||||||
def __init__(self, data_path, fast_mode=True):
|
def __init__(self, data_path, fast_mode=True):
|
||||||
self.data_path = data_path
|
self.data_path = data_path
|
||||||
self.df = None
|
self.df = None
|
||||||
@@ -441,7 +446,7 @@ class UltimateAIMLEurojackpotGenerator:
|
|||||||
"""High-EV: 2 Zahlen >31, max. 1 Lucky Number, soft Consecutive-Vermeidung."""
|
"""High-EV: 2 Zahlen >31, max. 1 Lucky Number, soft Consecutive-Vermeidung."""
|
||||||
random.seed(42 + tip_number * 41)
|
random.seed(42 + tip_number * 41)
|
||||||
|
|
||||||
lucky_numbers = {3, 7, 9, 11, 13, 17, 19, 21, 23}
|
lucky_numbers = UltimateAIMLEurojackpotGenerator.POPULAR_PLAYER_PICKS
|
||||||
above_31_target = 2 # für 5 Zahlen: 2 above-31 = solide EV-Basis
|
above_31_target = 2 # für 5 Zahlen: 2 above-31 = solide EV-Basis
|
||||||
|
|
||||||
selected_main = []
|
selected_main = []
|
||||||
@@ -671,41 +676,91 @@ class UltimateAIMLEurojackpotGenerator:
|
|||||||
return (distance_score * 0.6 + range_score * 0.4)
|
return (distance_score * 0.6 + range_score * 0.4)
|
||||||
|
|
||||||
def _get_smart_euro_numbers(self, tip_number, euro_preds):
|
def _get_smart_euro_numbers(self, tip_number, euro_preds):
|
||||||
"""Intelligente Euro-Zahlen Auswahl."""
|
"""
|
||||||
sorted_euro = sorted(euro_preds.items(), key=lambda x: x[1], reverse=True)
|
EV-bewusste Euro-Zahlen-Auswahl: gewichtete Zufallswahl aus den
|
||||||
|
AI-Predictions statt starrer Top-2 (vorher: Tipps 1-3 bekamen IMMER
|
||||||
|
exakt dasselbe Euro-Paar), mit Abwertung klassischer Glückszahlen
|
||||||
|
(3, 7) - analog zur Hauptzahlen-Logik in _generate_high_ev_tip().
|
||||||
|
|
||||||
# Strategy based on tip number
|
Schwächer empirisch belegt als die Hauptzahlen-Heuristik: 1-12
|
||||||
if tip_number <= 3:
|
überschneidet sich mit Kalendermonaten, es gibt keine klare
|
||||||
# Top predictions
|
Geburtstags-Grenze wie bei den Hauptzahlen (>31). Deshalb bewusst
|
||||||
return sorted([num for num, _ in sorted_euro[:2]])
|
konservativ: nur die zwei bekanntesten Glückszahlen abgewertet,
|
||||||
else:
|
keine erfundene Rangfolge aller 12 Ziffern.
|
||||||
# Mix of top and diversity
|
"""
|
||||||
top_euros = [num for num, _ in sorted_euro[:6]]
|
random.seed(100 + tip_number * 13)
|
||||||
random.seed(42 + tip_number * 7)
|
lucky_euro = {3, 7}
|
||||||
return sorted(random.sample(top_euros, 2))
|
|
||||||
|
pool = list(euro_preds.keys())
|
||||||
|
weights = []
|
||||||
|
for n in pool:
|
||||||
|
w = euro_preds.get(n, 0.1)
|
||||||
|
if n in lucky_euro:
|
||||||
|
w *= 0.5
|
||||||
|
weights.append(max(0.001, w))
|
||||||
|
|
||||||
|
chosen = []
|
||||||
|
for _ in range(2):
|
||||||
|
pick = random.choices(pool, weights=weights)[0]
|
||||||
|
idx = pool.index(pick)
|
||||||
|
pool.pop(idx)
|
||||||
|
weights.pop(idx)
|
||||||
|
chosen.append(pick)
|
||||||
|
|
||||||
|
return sorted(chosen)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _calculate_popularity_score(main_numbers):
|
def _calculate_popularity_score(main_numbers):
|
||||||
"""
|
"""
|
||||||
Schätzt den Erwartungswert-Vorteil durch Vermeidung populärer Zahlenkombinationen.
|
Schätzt den Erwartungswert-Vorteil durch Vermeidung populärer Zahlenkombinationen.
|
||||||
Höher = unpopulärer = höherer Gewinnanteil bei einem Treffer.
|
Höher = unpopulärer bei Mitspielern = höherer Gewinnanteil bei einem Treffer
|
||||||
Basis: Spieler bevorzugen Geburtstagszahlen (1-31), Glückszahlen und Zahlenfolgen.
|
(Hit-Wahrscheinlichkeit selbst ist bei i.i.d. Ziehungen nicht beeinflussbar).
|
||||||
|
|
||||||
|
Basis: dokumentierte Spielerverhalten-Biases (Henze/Riedwyl-artige Analysen
|
||||||
|
realer Tippscheine): Geburtstagszahlen (<=31), einzelne "griffige" Zahlen,
|
||||||
|
Zahlenfolgen/arithmetische Muster (z.B. 5-10-15-20-25) und "zufällig
|
||||||
|
aussehende" ausgeglichene Odd/Even-Splits werden von Menschen
|
||||||
|
überproportional oft gewählt - jede einzelne Kombination ist aber exakt
|
||||||
|
gleich wahrscheinlich, unabhängig von diesen Eigenschaften.
|
||||||
|
|
||||||
|
Hinweis: eine "Summe nahe am Mittel"-Komponente wurde bewusst NICHT
|
||||||
|
aufgenommen - sie widerspricht sich mit der Muster-Erkennung, da gerade
|
||||||
|
die meistgespielten sequenziellen Kombinationen (z.B. 1-2-3-4-5) durch
|
||||||
|
ihre enge Zahlen-Clusterung zugleich eine extreme Summe erzeugen.
|
||||||
"""
|
"""
|
||||||
n = len(main_numbers)
|
n = len(main_numbers)
|
||||||
sorted_nums = sorted(main_numbers)
|
sorted_nums = sorted(main_numbers)
|
||||||
|
|
||||||
# Anteil Zahlen > 31 (Geburtstags-Range vermeiden)
|
# 1) Geburtstags-Range (1-31) meiden
|
||||||
above_31_ratio = sum(1 for x in main_numbers if x > 31) / n
|
above_31_ratio = sum(1 for x in main_numbers if x > 31) / n
|
||||||
|
|
||||||
# Aufeinanderfolgende Zahlen vermeiden (visuelle Muster)
|
# 2) Empirisch belegte populäre Einzelzahlen meiden
|
||||||
consecutive_pairs = sum(1 for i in range(n - 1) if sorted_nums[i + 1] - sorted_nums[i] == 1)
|
popular_ratio = sum(
|
||||||
consecutive_ratio = consecutive_pairs / (n - 1) if n > 1 else 0
|
1 for x in main_numbers
|
||||||
|
if x in UltimateAIMLEurojackpotGenerator.POPULAR_PLAYER_PICKS
|
||||||
|
) / n
|
||||||
|
|
||||||
# Häufig gespielte "Glückszahlen" vermeiden
|
# 3) Muster/Zahlenfolgen meiden: direkte Nachbarn UND allgemeine
|
||||||
lucky_numbers = {3, 7, 9, 11, 13, 17, 19, 21, 23}
|
# arithmetische Folgen (konstante Schrittweite, z.B. 5-10-15-20-25
|
||||||
lucky_ratio = sum(1 for x in main_numbers if x in lucky_numbers) / n
|
# zählt zu den meistgespielten Kombinationen überhaupt)
|
||||||
|
diffs = [sorted_nums[i + 1] - sorted_nums[i] for i in range(n - 1)]
|
||||||
|
small_step_ratio = sum(1 for d in diffs if d <= 5) / (n - 1) if diffs else 0
|
||||||
|
is_perfect_progression = len(diffs) > 1 and len(set(diffs)) == 1
|
||||||
|
pattern_penalty = small_step_ratio * (0.6 if not is_perfect_progression else 1.0)
|
||||||
|
|
||||||
score = above_31_ratio * 0.5 + (1 - consecutive_ratio) * 0.3 + (1 - lucky_ratio) * 0.2
|
# 4) Odd/Even-Split: Menschen bevorzugen "ausgeglichen aussehende" Splits,
|
||||||
|
# obwohl jede einzelne Kombination gleich wahrscheinlich ist. Bei 5
|
||||||
|
# Zahlen ist der ausgeglichenste Split 2-3/3-2 (kein exaktes Halbieren
|
||||||
|
# möglich), daher Distanz zum Mittelpunkt 2.5 statt n/2.
|
||||||
|
even_count = sum(1 for x in main_numbers if x % 2 == 0)
|
||||||
|
split_extremity = abs(even_count - (n / 2)) / (n / 2)
|
||||||
|
|
||||||
|
score = (
|
||||||
|
above_31_ratio * 0.30
|
||||||
|
+ (1 - popular_ratio) * 0.20
|
||||||
|
+ (1 - pattern_penalty) * 0.30
|
||||||
|
+ split_extremity * 0.20
|
||||||
|
)
|
||||||
return min(max(score, 0.0), 1.0)
|
return min(max(score, 0.0), 1.0)
|
||||||
|
|
||||||
def _calculate_quality_score(self, main_numbers, euro_numbers, main_preds, euro_preds, pattern_weight):
|
def _calculate_quality_score(self, main_numbers, euro_numbers, main_preds, euro_preds, pattern_weight):
|
||||||
@@ -741,13 +796,17 @@ class UltimateAIMLEurojackpotGenerator:
|
|||||||
else:
|
else:
|
||||||
recency_quality = 0.5
|
recency_quality = 0.5
|
||||||
|
|
||||||
|
# Popularity/EV dominiert bewusst: AI-Score, Pattern und Recency sagen nichts
|
||||||
|
# über die (unbeeinflussbare) Trefferwahrscheinlichkeit aus - Recency/Pattern
|
||||||
|
# folgen zudem Heuristiken, die auch andere Systemspieler nutzen und damit die
|
||||||
|
# Popularity eher untergraben statt sie zu unterstützen.
|
||||||
quality = (
|
quality = (
|
||||||
main_quality * 0.25
|
main_quality * 0.15
|
||||||
+ euro_quality * 0.15
|
+ euro_quality * 0.10
|
||||||
+ pattern_quality * 0.15
|
+ pattern_quality * 0.10
|
||||||
+ diversity_quality * 0.10
|
+ diversity_quality * 0.10
|
||||||
+ popularity_quality * 0.20
|
+ popularity_quality * 0.45
|
||||||
+ recency_quality * 0.15
|
+ recency_quality * 0.10
|
||||||
)
|
)
|
||||||
return min(quality, 1.0)
|
return min(quality, 1.0)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user