MMR Berechnung sollte jeztt funktionieren. Muss noch testen.

Ein paar Tooltips verteilen wäre noch nett...
This commit is contained in:
Daniel Nagel 2026-03-16 15:04:08 +00:00
parent aaaf96caed
commit 931189baca
7 changed files with 178 additions and 329 deletions

View File

@ -1 +1 @@
{"authenticated":true,"discord_id":"277898241750859776","discord_name":"mrteels","db_id":2,"display_name":"Schwitzender Klebschnüffler","discord_avatar_url":"https://cdn.discordapp.com/avatars/277898241750859776/7c3446bb51fafd72b1b4c21124b4994f.png"}
{"authenticated":true,"discord_id":"277898241750859776","discord_name":"mrteels","db_id":2,"display_name":"Verwirrter Servitor","discord_avatar_url":"https://cdn.discordapp.com/avatars/277898241750859776/7c3446bb51fafd72b1b4c21124b4994f.png"}

View File

@ -70,8 +70,6 @@ def get_or_create_player(discord_id, discord_name, avatar_url):
return player
def get_all_players():
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
@ -88,8 +86,6 @@ def get_all_players():
return result
def get_all_players_from_system(system_name):
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
@ -119,6 +115,7 @@ def get_all_players_from_system(system_name):
return result
def get_gamesystem_id_by_name(system_name):
"""Holt die interne ID eines Spielsystems anhand seines Namens (z.B. 'Warhammer 40k' -> 1)."""
connection = sqlite3.connect(DB_PATH)
@ -138,32 +135,6 @@ def get_gamesystem_id_by_name(system_name):
return None
def get_player_rank(player_id, gamesystem_id):
"""Sortiert die Liga nach MMR und gibt den aktuellen Platz (Rang) des Spielers zurück."""
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
# Alle Spieler dieser Liga, sortiert nach MMR (höchstes zuerst)
query = """
SELECT player_id
FROM player_game_statistic
WHERE gamesystem_id = ?
ORDER BY mmr DESC
"""
cursor.execute(query, (gamesystem_id,))
rows = cursor.fetchall()
connection.close()
# Wir zählen die Liste durch (enumerate fängt bei 0 an, also machen wir +1 für den Rang)
for index, row in enumerate(rows):
if row['player_id'] == player_id:
return index + 1
# Falls der Spieler nicht in der Liga ist (sollte nicht passieren)
return 999
def get_gamesystem_data():
connection = sqlite3.connect(DB_PATH)
@ -305,173 +276,58 @@ def add_new_match(system_name, player1_id, player2_id, score_p1, score_p2):
def get_player_system_stats(player_id, system_name):
"""Holt die gespeicherten Statistiken eines Spielers für ein spezielles System direkt aus der Tabelle."""
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
# stat.* holt einfach ALLE Spalten, die in der Tabelle player_game_statistic stehen
query = """
SELECT stat.*
FROM player_game_statistic stat
JOIN gamesystems sys ON stat.gamesystem_id = sys.id
WHERE stat.player_id = ? AND sys.name = ?
"""
cursor.execute(query, (player_id, system_name))
row = cursor.fetchone()
connection.close()
# Wenn wir was finden, machen wir ein Dictionary draus, ansonsten geben wir None zurück
if row:
return dict(row)
logger.log("data_api/Get Player Data", "get_player_system_stats returned None. New player?")
return None
def get_last_20_match_scores(player_id, system_name):
"""Holt die erspielten Punkte und das Datum der letzten 20 Matches."""
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row
cursor = connection.cursor()
# NEU: Wir haben 'm.played_at' im SELECT hinzugefügt!
query = """
SELECT m.player1_id, m.score_player1, m.score_player2, m.played_at
FROM matches m
JOIN gamesystems sys ON m.gamesystem_id = sys.id
WHERE sys.name = ? AND (m.player1_id = ? OR m.player2_id = ?)
ORDER BY m.played_at DESC
LIMIT 20
"""
cursor.execute(query, (system_name, player_id, player_id))
rows = cursor.fetchall()
connection.close()
# Wieder umdrehen für den zeitlichen Verlauf (links alt, rechts neu)
rows.reverse()
points_list = []
labels_list = []
for row in rows:
if row['player1_id'] == player_id:
points_list.append(row['score_player1'])
else:
points_list.append(row['score_player2'])
# NEU: Wir schneiden das Datum ab (z.B. 2024-03-04) und nutzen es als Label!
date_clean = str(row['played_at'])[:10]
labels_list.append(date_clean)
return {"points": points_list, "labels": labels_list}
def get_match_by_id(match_id):
"""Holt alle Daten eines spezifischen Matches anhand der Match-ID."""
connection = sqlite3.connect(DB_PATH)
connection.row_factory = sqlite3.Row # Damit wir wieder ein schönes Dictionary bekommen
cursor = connection.cursor()
# m.* holt alle Spalten aus dem Match (Punkte, IDs, Datum)
# sys.name AS gamesystem_name holt uns direkt den passenden Text für deine JSON-Ladefunktion
query = """
SELECT m.*, sys.name AS gamesystem_name
FROM matches m
JOIN gamesystems sys ON m.gamesystem_id = sys.id
WHERE m.id = ?
"""
cursor.execute(query, (match_id,))
row = cursor.fetchone()
connection.close()
# Wenn ein Match gefunden wurde, geben wir es als Dictionary zurück
if row:
return dict(row)
return None # Falls die ID nicht existiert
from datetime import datetime
def get_days_since_last_game(player_id):
"""
Sucht das absolut letzte Spiel eines Spielers (über alle Systeme)
und berechnet, wie viele Tage das her ist.
"""
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
# MAX(last_played) sucht den absolut neuesten Zeitstempel aus allen Einträgen dieses Spielers
query = """
SELECT MAX(last_played)
FROM player_game_statistic
WHERE player_id = ?
"""
cursor.execute(query, (player_id,))
row = cursor.fetchone()
connection.close()
# row[0] enthält jetzt unseren Zeitstempel (z.B. '2026-03-05 14:30:00')
last_played_str = row[0] if row else None
# Sicherheitscheck: Hat der Spieler überhaupt schon Einträge?
if not last_played_str:
return None
try:
# [:19] schneidet Millisekunden ab, damit das Format exakt passt.
last_played_date = datetime.strptime(last_played_str[:19], '%Y-%m-%d %H:%M:%S')
# 2. Die Differenz zu "Jetzt genau in diesem Moment" berechnen
time_difference = datetime.now() - last_played_date
# 3. .days holt aus der Zeitdifferenz nur die reinen, vollen Tage heraus
days_ago = time_difference.days
return {
"date_string": last_played_str[:10], # Nur das Datum (YYYY-MM-DD) für die GUI
"days_ago": days_ago # Die nackte Zahl zum Rechnen (z.B. 14)
}
except ValueError:
# Falls in der Datenbank mal ein kaputter String steht
return None
# Eintragen eines berechneten Matches.
def save_calculated_match(results):
"""
Speichert alle Match-Details und aktualisiert gleichzeitig die Statistiken beider Spieler.
'results' ist ein Dictionary (dict) mit allen berechneten Werten.
"""
def save_calculated_match(calc_results: dict):
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
try:
# 1. Die Match-Tabelle updaten (Alle Detailwerte eintragen und als berechnet markieren)
match_id = calc_results["match_id"]
winner_id = calc_results["winner_id"]
looser_id = calc_results["looser_id"]
# Match aus DB lesen
cursor.execute(
"SELECT player1_id, player2_id, gamesystem_id FROM matches WHERE id = ?",
(match_id,)
)
row = cursor.fetchone()
if not row:
raise ValueError(f"Match ID {match_id} nicht in der Datenbank gefunden.")
player1_id, player2_id, gamesystem_id = row
# Daten der Spieler aus calc_results holen (Key = player_id als int/str)
p1 = calc_results[player1_id]
p2 = calc_results[player2_id]
# 1. Match-Tabelle updaten
match_query = """
UPDATE matches
SET
player1_base_change = ?, player1_khorne = ?, player1_slaanesh = ?, player1_tzeentch = ?, player1_mmr_change = ?,
player2_base_change = ?, player2_khorne = ?, player2_slaanesh = ?, player2_tzeentch = ?, player2_mmr_change = ?,
player1_base_change = ?, player1_khorne = ?, player1_slaanesh = ?,
player1_tzeentch = ?, player1_mmr_change = ?,
player2_base_change = ?, player2_khorne = ?, player2_slaanesh = ?,
player2_tzeentch = ?, player2_mmr_change = ?,
rust_factor = ?, elo_factor = ?, point_inflation = ?,
match_is_counted = 1
WHERE id = ?
"""
cursor.execute(match_query, (
results.get('p1_base', 0), results.get('p1_khorne', 0), results.get('p1_slaanesh', 0), results.get('p1_tzeentch', 0), results.get('p1_total', 0),
results.get('p2_base', 0), results.get('p2_khorne', 0), results.get('p2_slaanesh', 0), results.get('p2_tzeentch', 0), results.get('p2_total', 0),
results.get('rust_factor', 1.0), results.get('elo_factor', 0.5), results.get('point_inflation', 0.7),
results['match_id']
p1["base"], p1["khorne"], p1["slaanesh"], p1["tzeentch"], p1["total"],
p2["base"], p2["khorne"], p2["slaanesh"], p2["tzeentch"], p2["total"],
calc_results["rust_factor"], calc_results["elo_factor"], calc_results["point_inflation"],
match_id
))
# 2. Vorlage für das Update der Spieler-Statistiken
# 2. Scores holen
cursor.execute(
"SELECT score_player1, score_player2 FROM matches WHERE id = ?",
(match_id,)
)
score_row = cursor.fetchone()
score_p1, score_p2 = score_row if score_row else (0, 0)
# 3. Statistik-Query
stat_query = """
UPDATE player_game_statistic
SET
@ -483,41 +339,35 @@ def save_calculated_match(results):
WHERE player_id = ? AND gamesystem_id = ?
"""
# 3. Statistik für Spieler 1 überschreiben
# 4. Statistik Spieler 1
cursor.execute(stat_query, (
results.get('p1_total', 0), results.get('p1_score', 0), results.get('p1_score', 0),
results['p1_id'], results['gamesystem_id']
p1["total"], score_p1, score_p1,
player1_id, gamesystem_id
))
# 4. Statistik für Spieler 2 überschreiben
# 5. Statistik Spieler 2
cursor.execute(stat_query, (
results.get('p2_total', 0), results.get('p2_score', 0), results.get('p2_score', 0),
results['p2_id'], results['gamesystem_id']
p2["total"], score_p2, score_p2,
player2_id, gamesystem_id
))
# 5. WICHTIG: Erst jetzt (wenn alle 3 Befehle fehlerfrei durchliefen) speichern wir fest!
connection.commit()
# 6. Ein sauberer Log-Eintrag
# (Achtung: Stelle sicher, dass du deinen 'logger' hier richtig importiert hast)
logger.log("MATCH_CALC", f"Match ID {results['match_id']} wurde komplett berechnet und verbucht.")
logger.log("MATCH_CALC", f"Match ID {match_id} wurde komplett berechnet und verbucht.")
return True
except Exception as e:
# FAIL-SAFE: Wenn irgendwas schiefgeht, machen wir einen ROLLBACK!
# Die Datenbank wird auf den Stand vor dieser Funktion zurückgesetzt. Nichts wird gespeichert.
connection.rollback()
print(f"KRITISCHER FEHLER beim Speichern des Matches: {e}")
return False
finally:
# Die Verbindung wird am Ende immer geschlossen
connection.close()
# -----------------------------------------------------
# Get Data Funktionen
# -----------------------------------------------------
@ -550,6 +400,42 @@ def get_leaderboard(system_name):
return result
def get_match_by_id(match_id: int) -> dict | None:
"""Gibt alle Match-Daten inkl. Gamesystem-Name als Dict zurück."""
connection = sqlite3.connect(DB_PATH)
cursor = connection.cursor()
try:
cursor.execute("""
SELECT
m.id,
m.gamesystem_id,
g.name AS gamesystem_name,
m.player1_id,
m.score_player1,
m.player2_id,
m.score_player2,
m.played_at
FROM matches m
JOIN gamesystems g ON m.gamesystem_id = g.id
WHERE m.id = ?
""", (match_id,))
row = cursor.fetchone()
if not row:
return None
columns = [desc[0] for desc in cursor.description]
return dict(zip(columns, row))
except Exception as e:
print(f"Fehler beim Laden des Matches: {e}")
return None
finally:
connection.close()
def get_player_name(player_id):
"""Gibt den Namen eines Spielers im Format 'Anzeigename (Discordname)' zurück."""

View File

@ -12,5 +12,13 @@
"match_form_info": [
"Um ein Spiel einzutragen gibt einfach deine Punkte ein. Wähle deinen Gegner aus. Und gibt seine Punkte ein.",
"**ACHTUNG:** Ein Spieler ist nur als Gegner auswählbar wenn er sich in der Liga angemeldet hat!"
],
"tyrann_info":[
],
"prügelknabe_info":[
]
}

View File

@ -4,11 +4,9 @@ from data import data_api
from gui.info_text import info_system
def setup_routes():
# 1. Die {}-Klammern definieren eine dynamische Variable in der URL
@ui.page('/statistic/{systemname}', dark=True)
def gamesystem_statistic_page(systemname: str): # <--- WICHTIG: Hier fangen wir das Wort aus der URL auf!
def gamesystem_statistic_page(systemname: str):
# Sicherheitscheck: Ist der User eingeloggt?
if not app.storage.user.get('authenticated', False):
ui.navigate.to('/')
return
@ -16,9 +14,23 @@ def setup_routes():
gui_style.apply_design()
player_id = app.storage.user.get('db_id')
stats = data_api.get_player_system_stats(player_id, systemname)
all_stats = data_api.get_player_statistics(player_id)
# Passendes System anhand des Namens (case-insensitive) herausfiltern
system_stat = next(
(s for s in all_stats if s["gamesystem_name"].lower() == systemname.lower()),
None
)
if system_stat:
# None-Werte absichern
mmr = system_stat["mmr"] or 0
games = system_stat["games_in_system"] or 0
points = system_stat["points"] or 0
avv_points = system_stat.get("avv_points") or "-"
last_played_raw = system_stat.get("last_played")
last_played = str(last_played_raw)[:10] if last_played_raw else "-"
if stats:
with ui.header().classes('items-center justify-between bg-zinc-900 p-4 shadow-lg'):
ui.button(icon="arrow_back", on_click=lambda: ui.navigate.to('/')).props("round")
ui.button("Spiel eintragen", on_click=lambda: ui.navigate.to(f'/add-match/{systemname}'))
@ -26,24 +38,18 @@ def setup_routes():
with ui.column().classes('w-full items-center justify-center mt-10'):
ui.label(f'Deine Statistik in {systemname}').classes('text-3xl justify-center font-bold text-normaltext')
# --- BLOCK 1 (2 Karten) ---
# 1. Daten für die Rangliste holen
# --- BLOCK 1 (MMR & Rang | Rangliste) ---
leaderboard_data = data_api.get_leaderboard(systemname)
# 2. Tabelle vorbereiten und den EIGENEN Rang herausfinden
table_rows = []
my_rank = "-"
for index, player in enumerate(leaderboard_data):
current_rank = index + 1
# Wenn wir in der Liste über uns selbst stolpern, merken wir uns den Rang für unsere Karte!
if player['id'] == player_id:
my_rank = current_rank
table_rows.append({
'rank': current_rank,
'trend': '', # Platzhalter für später
'trend': '',
'name': f"{player['display_name']} 'aka' {player['discord_name']}",
'mmr': player['mmr']
})
@ -52,11 +58,9 @@ def setup_routes():
{'name': 'rank', 'label': '#', 'field': 'rank', 'align': 'left'},
{'name': 'trend', 'label': 'Trend', 'field': 'trend', 'align': 'center'},
{'name': 'name', 'label': 'Spieler', 'field': 'name', 'align': 'left'},
{'name': 'mmr', 'label': 'MMR', 'field': 'mmr', 'align': 'left'}
{'name': 'mmr', 'label': 'MMR', 'field': 'mmr', 'align': 'left'},
]
# --- BLOCK 1 (Links: MMR & Rang | Rechts: Rangliste) ---
# lg:grid-cols-3 teilt den Bildschirm auf großen Monitoren in 3 gleich große unsichtbare Spalten
with ui.element('div').classes("w-full grid grid-cols-1 lg:grid-cols-3 gap-4 mt-4"):
with ui.column().classes("w-full gap-4"):
with ui.card().classes("w-full items-center justify-center text-center"):
@ -64,30 +68,27 @@ def setup_routes():
ui.label("MMR Punkte: ").classes('justify-center text-2xl font-bold text-normaltext')
ui.space()
info_system.create_info_button("mmr_info")
ui.label(str(stats["mmr"])).classes('text-4xl font-bold text-accent')
ui.label(str(mmr)).classes('text-4xl font-bold text-accent')
with ui.card().classes("w-full items-center justify-center text-center"):
ui.label("Rang: ").classes('text-2xl font-bold')
# Hier tragen wir jetzt unsere gefundene Platzierung ein!
ui.label(str(my_rank)).classes('text-4xl font-bold text-blue-100')
# RECHTE SEITE (Belegt 2 Spalten -> lg:col-span-2)
with ui.card().classes("w-full lg:col-span-2"):
ui.label("Liga Rangliste").classes("text-xl font-bold text-white mb-2")
ui.table(columns=table_columns, rows=table_rows, row_key='rank').classes('w-full bg-zinc-900 text-white')
# --- BLOCK 2 (5 Karten) ---
with ui.card().classes("w-full"):
with ui.element('div').classes("w-full grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4"):
with ui.card().classes("items-center justify-center text-center"):
ui.label("Spiele: ").classes('text-2xl font-bold')
ui.label(str(stats["games_in_system"])).classes('text-4xl font-bold text-blue-100')
ui.label(str(games)).classes('text-4xl font-bold text-blue-100')
with ui.card().classes("items-center justify-center text-center"):
ui.label("Ø Punkte pro Spiel: ").classes('text-2xl font-bold')
ui.label(str(stats["avv_points"])).classes('text-4xl font-bold text-blue-100')
ui.label(str(avv_points)).classes('text-4xl font-bold text-blue-100')
with ui.card().classes("items-center justify-center text-center"):
ui.label("Win-Rate: ").classes('text-2xl font-bold')
@ -95,8 +96,6 @@ def setup_routes():
with ui.card().classes("items-center justify-center text-center"):
ui.label("Letztes Spiel am: ").classes('text-2xl font-bold')
# Schneidet die Zeit vom Datum ab, falls eins existiert
last_played = str(stats["last_played"])[:10] if stats["last_played"] else "-"
ui.label(last_played).classes('text-4xl font-bold text-blue-100')
with ui.card().classes("items-center justify-center text-center"):
@ -119,52 +118,6 @@ def setup_routes():
ui.label("Dein 'Prügelknabe': ").classes('text-2xl font-bold')
ui.label("-").classes('text-4xl font-bold text-blue-100')
# --- BLOCK 4 (Diagramm der letzten 20 Spiele) ---
with ui.card().classes("w-full items-center"):
ui.label("Punkte in den letzten 20 Spielen").classes('text-2xl font-bold mb-4')
# 1. Daten aus der API holen
chart_data = data_api.get_last_20_match_scores(player_id, systemname)
# 2. Nur zeichnen, wenn es überhaupt schon Spiele gibt!
if len(chart_data['points']) > 0:
ui.echart({
'xAxis': {
'type': 'category',
'data': chart_data['labels'],
'axisLabel': {'color': '#e5e7eb'}
},
'yAxis': {
'type': 'value',
'axisLabel': {'color': '#e5e7eb'},
'splitLine': {'lineStyle': {'color': '#3f3f46'}}
},
'series': [
{
'name': 'Punkte', # Zeigt im Tooltip "Punkte: 76" statt einer unbenannten Zahl
'type': 'line',
'data': chart_data['points'],
'smooth': True,
'color': '#60a5fa'
}
],
'tooltip': {
'trigger': 'axis',
'backgroundColor': '#27272a',
'textStyle': {'color': '#ffffff'},
'borderColor': '#3f3f46' # Ein feiner Rand für den Kasten
}
}).classes('w-full h-64')
else:
ui.label("Keine Statistiken für dieses System gefunden.").classes('text-red-500 mt-4')
with ui.column().classes('w-full items-center justify-center mt-10'):
ui.label(f'Keine Statistik für "{systemname}" gefunden.').classes('text-red-500 text-xl mt-4')

View File

@ -128,6 +128,7 @@ def setup_routes(admin_discord_id):
def acccept_match(m_id):
ui.notify("Spiel akzeptiert. Wird Berechnet.")
ui.navigate.reload() # Lädt die Seite neu, um die Karte zu aktualisieren
data_api.confirm_match(m_id)
calc_match.calculate_match(m_id)
with ui.row().classes('w-full items-center justify-between bg-zinc-900 p-3 rounded shadow-inner'):

View File

@ -6,7 +6,7 @@ from wood import logger
point_inflation = 0.7 # => entspricht %
K_FACTOR = 40 # Die "Border" (Maximalpunkte) die ein Sieg gibt.
K_FACTOR = 30 # Die "Border" (Maximalpunkte) die ein Sieg gibt.
# Mach die DB abfrage für die Relevanten Daten. Von hier aus werden die "Aufgaben" und Daten dann an die kleineren Berechnungs Funktionen verteilt.
def calculate_match (match_id):
@ -16,20 +16,19 @@ def calculate_match (match_id):
print("Fehler: Match nicht gefunden!")
return
data_api.confirm_match(match_id)
# Laden und aufdröseln der Match Daten
p1_id = match_data['player1_id']
p2_id = match_data['player2_id']
p1_score = match_data['score_player1']
p2_score = match_data['score_player2']
sys_name = match_data['gamesystem_name']
sys_id = match_data['gamesystem_id']
system_name = match_data['gamesystem_name']
system_id = match_data['gamesystem_id']
match_is_draw = False
draw_diff = determine_draw_diff(system_id)
# ==========================================
# 1. IDENTIFIKATION (Bleibt gleich)
# 1. IDENTIFIKATION
# ==========================================
# Draw
if -draw_diff <= (p1_score - p2_score) <= draw_diff:
@ -52,20 +51,20 @@ def calculate_match (match_id):
# Wir speichern die Ergebnisse direkt in einem temporären Dictionary,
# und nutzen die SPIELER-ID als Schlüsselwort!
elo_factor = calculation.calc_elo_factor(winner_id, looser_id, system_name)
base_change = calculation.calc_base_change(elo_factor, match_is_draw)
rust_factor = calculation.calc_rust_factor(winner_id, looser_id, gamesystem_id)
base_change = int(calculation.calc_base_change(elo_factor, match_is_draw, K_FACTOR))
rust_factor = calculation.calc_rust_factor(winner_id, looser_id, system_id)
#winner
w_base = base_change
w_khorne = calculation.wrath_of_khorne(winner_id)
w_base = int(base_change)
w_khorne = int(calculation.wrath_of_khorne(winner_id, system_id))
#looser
l_base = int(base_change*point_inflation)
l_khorne = calculation.wrath_of_khorne(looser_id)
slaanesh = calculation.slaanesh_delight(),
tzeentch = calculation.tzeentch_scemes(winner_score, looser_score),
l_khorne = int(calculation.wrath_of_khorne(looser_id, system_id))
slaanesh = int(calculation.slaanesh_delight())
tzeentch = int(calculation.tzeentch_scemes(winner_score, looser_score))
# ==========================================
@ -77,24 +76,26 @@ def calculate_match (match_id):
"rust_factor" : rust_factor,
"point_inflation" : point_inflation,
winner_id: {
"base": w_base,
"khorne": w_khorne,
"slaanesh": slaanesh,
"tzeentch": tzeentch,
"total": int((w_base + w_khorne + slaanesh + tzeentch)*rust_factor),
"winner_id" : winner_id, # <-- String-Key für save_calculated_match
"looser_id" : looser_id, # <-- String-Key für save_calculated_match
winner_id: { # <-- Variable als Key (z.B. 42: {...})
"base" : w_base,
"khorne" : w_khorne,
"slaanesh" : slaanesh,
"tzeentch" : tzeentch,
"total" : int((w_base + w_khorne + slaanesh + tzeentch) * rust_factor),
},
looser_id: {
"base": l_base,
"khorne": l_khorne,
"slaanesh": -slaanesh,
"tzeentch": calculation.tzeentch_scemes(winner_score, looser_score),
"total": int((calc_results[looser_id]["base"] + calc_results[looser_id]["khorne"] - calc_results[looser_id]["slaanesh"] - calc_results[looser_id]["tzeentch"])*calc_results["rust_factor"]),
looser_id: { # <-- Variable als Key (z.B. 7: {...})
"base" : -l_base,
"khorne" : l_khorne,
"slaanesh" : -slaanesh,
"tzeentch" : -tzeentch,
"total" : int((-l_base + l_khorne - slaanesh - tzeentch) * rust_factor),
}
}
data_api.save_calculated_match(calc_results)
def determine_draw_diff(sys_id):
@ -104,5 +105,4 @@ def determine_draw_diff(sys_id):
draw_diff = 3
case 2,3:
draw_diff = 1
return draw_diff

View File

@ -5,7 +5,7 @@ from wood import logger
# die meisten Spieler über 1000MMR sein. Sprich: Neueinsteiger, oder leute die weniger spielen sind eher im unteren Ende als in der Mitte.
def calc_base_change(elo_factor, match_is_draw):
def calc_base_change(elo_factor, match_is_draw, K_FACTOR):
if match_is_draw:
# Bei einem Draw (0.5) gewinnt der Schwächere leicht Punkte, der Stärkere verliert leicht.
base_change = (K_FACTOR * (0.5 - elo_factor)/2)
@ -13,19 +13,21 @@ def calc_base_change(elo_factor, match_is_draw):
# Sieg (1.0). Gewinnt der Favorit, gibt es wenig Punkte. Gewinnt der Underdog, gibt es viele!
base_change = K_FACTOR * (1.0 - elo_factor)
return base_change
def calc_elo_factor(winner_id, looser_id, system_name):
w_stats = data_api.get_player_statistics(winner_id)
l_stats = data_api.get_player_statistics(looser_id)
# ------------------------------------------
# 1. Die aktuellen MMR-Punkte holen
w_stat = data_api.get_player_system_stats(winner_id, systemname)
l_stat = data_api.get_player_system_stats(looser_id, systemname)
# Passendes System aus der Liste herausfiltern
w_stat = next((s for s in w_stats if s['gamesystem_name'] == system_name), None)
l_stat = next((s for s in l_stats if s['gamesystem_name'] == system_name), None)
# Wenn ein Spieler noch keine keine Stats hat wird None zurück gegeben. Fallback für diesen Fall
w_mmr = w_stat['mmr'] if w_stat and w_stat['mmr'] is not None else 1000
l_mmr = l_stat['mmr'] if l_stat and l_stat['mmr'] is not None else 1000
return (1 / (1 + 10 ** ((l_mmr - w_mmr)/400)))
return (1 / (1 + 10 ** ((l_mmr - w_mmr) / 400)))
@ -36,8 +38,7 @@ def calc_rust_factor(winner_id, looser_id, gamesystem_id):
l_days = data_api.get_days_since_last_system_game(looser_id, gamesystem_id)
# Der größeren der beiden Werte wird verwendet.
days = max(w_days, l_days)
rust_factor = get_rust_dampener(days)
days_ago = max(w_days, l_days)
"""Berechnet den Dämpfungsfaktor basierend auf den vergangen Tagen."""
if days_ago <= 30:
@ -51,20 +52,20 @@ def calc_rust_factor(winner_id, looser_id, gamesystem_id):
return round(factor, 2)
def wrath_of_khorne(player_id):
def wrath_of_khorne(player_id, system_id):
# -----------------
khorne_days = 16
khorne_bonus = 8
# -----------------
last_played = data_api.get_days_since_last_game(player_id)["days_ago"]
last_played = int(data_api.get_days_since_last_system_game(player_id, system_id))
if last_played <= khorne_days:
return khorne_bonus
else:
return 0
def slaanesh_delight():
return 0
def tzeentch_scemes(winner_score, looser_score):
return 0