Erstellen der mmr_rules Matrix. Berechnung der Matches, erster Teil. Aufsetzten der MMR Berechnung.
This commit is contained in:
parent
cd2050e6fe
commit
0f914f3117
|
|
@ -1 +1 @@
|
||||||
{"authenticated":true,"discord_id":"277898241750859776","discord_name":"mrteels","db_id":2,"display_name":"Daniel Nagel","discord_avatar_url":"https://cdn.discordapp.com/avatars/277898241750859776/7c3446bb51fafd72b1b4c21124b4994f.png"}
|
{"authenticated":true,"discord_id":"277898241750859776","discord_name":"mrteels","db_id":2,"display_name":"Verzweifelter Regelvergesser","discord_avatar_url":"https://cdn.discordapp.com/avatars/277898241750859776/7c3446bb51fafd72b1b4c21124b4994f.png"}
|
||||||
|
|
@ -99,9 +99,49 @@ def get_all_players_from_system(system_name):
|
||||||
|
|
||||||
return result
|
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)
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
import sqlite3
|
# Wir suchen exakt nach dem Namen
|
||||||
from data.setup_database import DB_PATH
|
cursor.execute("SELECT id FROM gamesystems WHERE name = ?", (system_name,))
|
||||||
|
row = cursor.fetchone()
|
||||||
|
|
||||||
|
connection.close()
|
||||||
|
|
||||||
|
# Wenn wir einen Treffer haben, geben wir die erste Spalte (die ID) zurück
|
||||||
|
if row:
|
||||||
|
return row[0]
|
||||||
|
|
||||||
|
# Wenn das System nicht existiert
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -224,7 +264,7 @@ def add_new_match(system_name, player1_id, player2_id, score_p1, score_p2):
|
||||||
# Sicherheitscheck (sollte eigentlich nie passieren)
|
# Sicherheitscheck (sollte eigentlich nie passieren)
|
||||||
if not sys_row:
|
if not sys_row:
|
||||||
connection.close()
|
connection.close()
|
||||||
return False
|
return None
|
||||||
|
|
||||||
sys_id = sys_row[0]
|
sys_id = sys_row[0]
|
||||||
|
|
||||||
|
|
@ -235,11 +275,12 @@ def add_new_match(system_name, player1_id, player2_id, score_p1, score_p2):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
cursor.execute(query, (sys_id, player1_id, player2_id, score_p1, score_p2))
|
cursor.execute(query, (sys_id, player1_id, player2_id, score_p1, score_p2))
|
||||||
|
new_match_id = cursor.lastrowid
|
||||||
|
|
||||||
connection.commit()
|
connection.commit()
|
||||||
connection.close()
|
connection.close()
|
||||||
|
|
||||||
return True
|
return new_match_id
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -306,3 +347,32 @@ def get_last_20_match_scores(player_id, system_name):
|
||||||
return {"points": points_list, "labels": labels_list}
|
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
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,5 +1,7 @@
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import os
|
import os
|
||||||
|
import json
|
||||||
|
|
||||||
|
|
||||||
DB_PATH = "data/warhammer_league.db"
|
DB_PATH = "data/warhammer_league.db"
|
||||||
|
|
||||||
|
|
@ -117,6 +119,7 @@ def seed_gamesystems():
|
||||||
print("Spielsysteme angelegt!")
|
print("Spielsysteme angelegt!")
|
||||||
|
|
||||||
#Nächster Schritt: Standard Achievments eintragen.
|
#Nächster Schritt: Standard Achievments eintragen.
|
||||||
|
generate_default_mmr_rules()
|
||||||
seed_achievements()
|
seed_achievements()
|
||||||
|
|
||||||
def seed_achievements():
|
def seed_achievements():
|
||||||
|
|
@ -179,3 +182,75 @@ def seed_dummy_player():
|
||||||
connection.close()
|
connection.close()
|
||||||
print("Test-Gegner 'Dummy Mc DummDumm' ist bereit und in allen Ligen angemeldet!")
|
print("Test-Gegner 'Dummy Mc DummDumm' ist bereit und in allen Ligen angemeldet!")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def generate_default_mmr_rules():
|
||||||
|
"""Erstellt für jedes Spielsystem eine Standard-JSON-Datei, falls sie noch nicht existiert."""
|
||||||
|
connection = sqlite3.connect(DB_PATH)
|
||||||
|
cursor = connection.cursor()
|
||||||
|
|
||||||
|
cursor.execute("SELECT name FROM gamesystems")
|
||||||
|
systems = cursor.fetchall()
|
||||||
|
connection.close()
|
||||||
|
|
||||||
|
# 1. Sicherstellen, dass der Ordner existiert (Best Practice!)
|
||||||
|
folder_path = "mmr_calculations"
|
||||||
|
os.makedirs(folder_path, exist_ok=True)
|
||||||
|
|
||||||
|
# 2. Wir gehen jedes gefundene Spielsystem durch
|
||||||
|
for sys in systems:
|
||||||
|
sys_name = sys[0]
|
||||||
|
|
||||||
|
# Wir machen den Namen "dateisicher" (z.B. "Warhammer 40k" -> "warhammer_40k")
|
||||||
|
safe_name = sys_name.replace(" ", "_").lower()
|
||||||
|
file_path = os.path.join(folder_path, f"mmr_rules_{safe_name}.json")
|
||||||
|
|
||||||
|
# 3. SICHERHEITS-CHECK: Existiert die Datei schon?
|
||||||
|
# Wenn ja, ignorieren wir sie, damit wir dein händisches Balancing nicht überschreiben!
|
||||||
|
if not os.path.exists(file_path):
|
||||||
|
|
||||||
|
# Das ist unsere Standard-Vorlage (Faktor 10)
|
||||||
|
default_rules = {
|
||||||
|
"system_info": f"Balancing für {sys_name}",
|
||||||
|
"draw_point_difference": 5,
|
||||||
|
"rank_matrix": {
|
||||||
|
"10": {"win": 10, "draw": 30},
|
||||||
|
"9": {"win": 10, "draw": 30},
|
||||||
|
"8": {"win": 10, "draw": 20},
|
||||||
|
"7": {"win": 10, "draw": 20},
|
||||||
|
"6": {"win": 20, "draw": 10},
|
||||||
|
"5": {"win": 20, "draw": 10},
|
||||||
|
"4": {"win": 20, "draw": 0},
|
||||||
|
"3": {"win": 20, "draw": 0},
|
||||||
|
"2": {"win": 30, "draw": 0},
|
||||||
|
"1": {"win": 30, "draw": 0},
|
||||||
|
"0": {"win": 30, "draw": 0},
|
||||||
|
"-1": {"win": 30, "draw": 0},
|
||||||
|
"-2": {"win": 40, "draw": 0},
|
||||||
|
"-3": {"win": 40, "draw": -10},
|
||||||
|
"-4": {"win": 50, "draw": -20},
|
||||||
|
"-5": {"win": 60, "draw": -20},
|
||||||
|
"-6": {"win": 70, "draw": -20},
|
||||||
|
"-7": {"win": 80, "draw": -50},
|
||||||
|
"-8": {"win": 100, "draw": -50},
|
||||||
|
"-9": {"win": 120, "draw": -60},
|
||||||
|
"-10": {"win": 150, "draw": -60}
|
||||||
|
},
|
||||||
|
"score_bonus": [
|
||||||
|
{"min_diff": 95, "bonus": 40},
|
||||||
|
{"min_diff": 85, "bonus": 30},
|
||||||
|
{"min_diff": 65, "bonus": 20},
|
||||||
|
{"min_diff": 35, "bonus": 10},
|
||||||
|
{"min_diff": 0, "bonus": 0}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
# 4. JSON-Datei schreiben
|
||||||
|
# 'w' steht für write (schreiben). indent=4 macht es für Menschen schön lesbar formatiert.
|
||||||
|
with open(file_path, 'w', encoding='utf-8') as f:
|
||||||
|
json.dump(default_rules, f, indent=4, ensure_ascii=False)
|
||||||
|
|
||||||
|
print(f"Neu: Balancing-Datei für '{sys_name}' wurde erstellt -> {file_path}")
|
||||||
|
else:
|
||||||
|
print(f"OK: Balancing-Datei für '{sys_name}' existiert bereits.")
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from nicegui import ui, app
|
from nicegui import ui, app
|
||||||
from gui import gui_style
|
from gui import gui_style
|
||||||
from data import data_api
|
from data import data_api
|
||||||
|
from mmr_calculations import calc_match
|
||||||
|
|
||||||
def setup_routes():
|
def setup_routes():
|
||||||
|
|
||||||
|
|
@ -54,6 +55,7 @@ def setup_routes():
|
||||||
|
|
||||||
ui.space()
|
ui.space()
|
||||||
|
|
||||||
|
# Das Match in die Datenbank eintragen lassen und die MMR Berechnung triggern.
|
||||||
def input_match_to_database():
|
def input_match_to_database():
|
||||||
# 1. Prüfen, ob ein Gegner ausgewählt wurde
|
# 1. Prüfen, ob ein Gegner ausgewählt wurde
|
||||||
p2_id = opponent_select.value
|
p2_id = opponent_select.value
|
||||||
|
|
@ -66,10 +68,11 @@ def setup_routes():
|
||||||
score_p2 = p2_points.value
|
score_p2 = p2_points.value
|
||||||
|
|
||||||
# 3. Daten an die API schicken (my_id haben wir oben schon von app.storage.user geholt)
|
# 3. Daten an die API schicken (my_id haben wir oben schon von app.storage.user geholt)
|
||||||
data_api.add_new_match(systemname, my_id, p2_id, score_p1, score_p2)
|
match_id = data_api.add_new_match(systemname, my_id, p2_id, score_p1, score_p2)
|
||||||
|
|
||||||
# 4. Erfolgsmeldung und zurück zur Übersicht
|
# 4. Erfolgsmeldung und zurück zur Übersicht
|
||||||
ui.notify("Match erfolgreich eingetragen!", color="green")
|
ui.notify("Match erfolgreich eingetragen!", color="green")
|
||||||
|
calc_match.calculate_inserted_match(systemname, match_id)
|
||||||
ui.navigate.to('/')
|
ui.navigate.to('/')
|
||||||
|
|
||||||
with ui.row().classes("w-full items-center justify-between"):
|
with ui.row().classes("w-full items-center justify-between"):
|
||||||
|
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
from data import database
|
|
||||||
62
mmr_calculations/calc_match.py
Normal file
62
mmr_calculations/calc_match.py
Normal file
|
|
@ -0,0 +1,62 @@
|
||||||
|
from data import data_api
|
||||||
|
from mmr_calculations import *
|
||||||
|
|
||||||
|
# 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_inserted_match (gamesystem, match_id):
|
||||||
|
match_data = data_api.get_match_by_id(match_id)
|
||||||
|
if not match_data:
|
||||||
|
print("Fehler: Match nicht gefunden!")
|
||||||
|
return
|
||||||
|
# Laden und umsetzen 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']
|
||||||
|
|
||||||
|
rules = load_mmr_rule_matrix(systemname)
|
||||||
|
draw_diff = rules["draw_point_difference"]
|
||||||
|
|
||||||
|
calculated = False
|
||||||
|
winner_id = None
|
||||||
|
looser_id = None
|
||||||
|
match_is_draw = False
|
||||||
|
winner_score = 0
|
||||||
|
looser_score = 0
|
||||||
|
|
||||||
|
# Abgrenzen ob das Match schon berechnet wurde. Weil ein Draw kan 4 Punkte unterschied haben
|
||||||
|
# 43-41 ist ein Draw aber rein Mathematisch würde es auch ein anderes if triggern
|
||||||
|
while not calculated:
|
||||||
|
# Match is a Draw
|
||||||
|
if -draw_diff <= (p1_score-p2_score) <= draw_diff:
|
||||||
|
match_is_draw = True
|
||||||
|
winner_id = p1_id
|
||||||
|
looser_id = p2_id
|
||||||
|
winner_score = p1_score
|
||||||
|
looser_score = p2_score
|
||||||
|
|
||||||
|
calculated = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# p1 ist der Sieger.
|
||||||
|
if score_p1 > score_p2:
|
||||||
|
winner_id = p1_id
|
||||||
|
looser_id = p2_id
|
||||||
|
winner_score = p1_score
|
||||||
|
looser_score = p2_score
|
||||||
|
|
||||||
|
calculated = True
|
||||||
|
break
|
||||||
|
|
||||||
|
# p2 ist der Sieger.
|
||||||
|
if score_p1 < score_p2:
|
||||||
|
winner_id = p2_id
|
||||||
|
looser_id = p1_id
|
||||||
|
winner_score = p2_score
|
||||||
|
looser_score = p1_score
|
||||||
|
|
||||||
|
calculated = True
|
||||||
|
break
|
||||||
|
|
||||||
|
calc_mmr_change.calc_mmr_change(sys_name, winner_id, looser_id, winner_score, looser_score, match_is_draw)
|
||||||
29
mmr_calculations/calc_mmr_change.py
Normal file
29
mmr_calculations/calc_mmr_change.py
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
from data import data_api
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
|
||||||
|
def calc_mmr_change(systemname, winner_id, looser_id, winner_points, looser_points, match_is_draw):
|
||||||
|
gamesystem_id = data_api.get_gamesystem_id_by_name(systemname)
|
||||||
|
winner_rank = data_api.get_player_rank(winner_id,gamesystem_id)
|
||||||
|
looser_rank = data_api.get_player_rank(looser_id, gamesystem_id)
|
||||||
|
|
||||||
|
rules = load_mmr_rule_matrix(systemname)
|
||||||
|
|
||||||
|
if match_is_draw:
|
||||||
|
mmr_change = rules["rank_matrix"][str(winner_rank-looser_rank)]["draw"]
|
||||||
|
|
||||||
|
else:
|
||||||
|
mmr_change = rules["rank_matrix"][str(winner_rank-looser_rank)]["win"]
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def load_mmr_rule_matrix(systemname):
|
||||||
|
safe_name = systemname.replace(" ", "_").lower()
|
||||||
|
|
||||||
|
file_path = f"mmr_calculations/mmr_rules_{safe_name}.json"
|
||||||
|
with open(file_path, "r", encoding="utf-8") as file:
|
||||||
|
rules = json.load(file)
|
||||||
|
|
||||||
|
return rules
|
||||||
|
|
||||||
112
mmr_calculations/mmr_rules_spearhead.json
Normal file
112
mmr_calculations/mmr_rules_spearhead.json
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
{
|
||||||
|
"system_info": "Balancing für Spearhead",
|
||||||
|
"draw_point_difference": 5,
|
||||||
|
"rank_matrix": {
|
||||||
|
"10": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 30
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 30
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 20
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 20
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 10
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 10
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"0": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"-1": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"-2": {
|
||||||
|
"win": 40,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"-3": {
|
||||||
|
"win": 40,
|
||||||
|
"draw": -10
|
||||||
|
},
|
||||||
|
"-4": {
|
||||||
|
"win": 50,
|
||||||
|
"draw": -20
|
||||||
|
},
|
||||||
|
"-5": {
|
||||||
|
"win": 60,
|
||||||
|
"draw": -20
|
||||||
|
},
|
||||||
|
"-6": {
|
||||||
|
"win": 70,
|
||||||
|
"draw": -20
|
||||||
|
},
|
||||||
|
"-7": {
|
||||||
|
"win": 80,
|
||||||
|
"draw": -50
|
||||||
|
},
|
||||||
|
"-8": {
|
||||||
|
"win": 100,
|
||||||
|
"draw": -50
|
||||||
|
},
|
||||||
|
"-9": {
|
||||||
|
"win": 120,
|
||||||
|
"draw": -60
|
||||||
|
},
|
||||||
|
"-10": {
|
||||||
|
"win": 150,
|
||||||
|
"draw": -60
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"score_bonus": [
|
||||||
|
{
|
||||||
|
"min_diff": 95,
|
||||||
|
"bonus": 40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 85,
|
||||||
|
"bonus": 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 65,
|
||||||
|
"bonus": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 35,
|
||||||
|
"bonus": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 0,
|
||||||
|
"bonus": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
112
mmr_calculations/mmr_rules_warhammer_40k.json
Normal file
112
mmr_calculations/mmr_rules_warhammer_40k.json
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
{
|
||||||
|
"system_info": "Balancing für Warhammer 40k",
|
||||||
|
"draw_point_difference": 5,
|
||||||
|
"rank_matrix": {
|
||||||
|
"10": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 30
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 30
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 20
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 20
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 10
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 10
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"0": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"-1": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"-2": {
|
||||||
|
"win": 40,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"-3": {
|
||||||
|
"win": 40,
|
||||||
|
"draw": -10
|
||||||
|
},
|
||||||
|
"-4": {
|
||||||
|
"win": 50,
|
||||||
|
"draw": -20
|
||||||
|
},
|
||||||
|
"-5": {
|
||||||
|
"win": 60,
|
||||||
|
"draw": -20
|
||||||
|
},
|
||||||
|
"-6": {
|
||||||
|
"win": 70,
|
||||||
|
"draw": -20
|
||||||
|
},
|
||||||
|
"-7": {
|
||||||
|
"win": 80,
|
||||||
|
"draw": -50
|
||||||
|
},
|
||||||
|
"-8": {
|
||||||
|
"win": 100,
|
||||||
|
"draw": -50
|
||||||
|
},
|
||||||
|
"-9": {
|
||||||
|
"win": 120,
|
||||||
|
"draw": -60
|
||||||
|
},
|
||||||
|
"-10": {
|
||||||
|
"win": 150,
|
||||||
|
"draw": -60
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"score_bonus": [
|
||||||
|
{
|
||||||
|
"min_diff": 95,
|
||||||
|
"bonus": 40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 85,
|
||||||
|
"bonus": 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 65,
|
||||||
|
"bonus": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 35,
|
||||||
|
"bonus": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 0,
|
||||||
|
"bonus": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
112
mmr_calculations/mmr_rules_warhammer_age_of_sigmar.json
Normal file
112
mmr_calculations/mmr_rules_warhammer_age_of_sigmar.json
Normal file
|
|
@ -0,0 +1,112 @@
|
||||||
|
{
|
||||||
|
"system_info": "Balancing für Warhammer Age of Sigmar",
|
||||||
|
"draw_point_difference": 5,
|
||||||
|
"rank_matrix": {
|
||||||
|
"10": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 30
|
||||||
|
},
|
||||||
|
"9": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 30
|
||||||
|
},
|
||||||
|
"8": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 20
|
||||||
|
},
|
||||||
|
"7": {
|
||||||
|
"win": 10,
|
||||||
|
"draw": 20
|
||||||
|
},
|
||||||
|
"6": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 10
|
||||||
|
},
|
||||||
|
"5": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 10
|
||||||
|
},
|
||||||
|
"4": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"3": {
|
||||||
|
"win": 20,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"2": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"1": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"0": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"-1": {
|
||||||
|
"win": 30,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"-2": {
|
||||||
|
"win": 40,
|
||||||
|
"draw": 0
|
||||||
|
},
|
||||||
|
"-3": {
|
||||||
|
"win": 40,
|
||||||
|
"draw": -10
|
||||||
|
},
|
||||||
|
"-4": {
|
||||||
|
"win": 50,
|
||||||
|
"draw": -20
|
||||||
|
},
|
||||||
|
"-5": {
|
||||||
|
"win": 60,
|
||||||
|
"draw": -20
|
||||||
|
},
|
||||||
|
"-6": {
|
||||||
|
"win": 70,
|
||||||
|
"draw": -20
|
||||||
|
},
|
||||||
|
"-7": {
|
||||||
|
"win": 80,
|
||||||
|
"draw": -50
|
||||||
|
},
|
||||||
|
"-8": {
|
||||||
|
"win": 100,
|
||||||
|
"draw": -50
|
||||||
|
},
|
||||||
|
"-9": {
|
||||||
|
"win": 120,
|
||||||
|
"draw": -60
|
||||||
|
},
|
||||||
|
"-10": {
|
||||||
|
"win": 150,
|
||||||
|
"draw": -60
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"score_bonus": [
|
||||||
|
{
|
||||||
|
"min_diff": 95,
|
||||||
|
"bonus": 40
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 85,
|
||||||
|
"bonus": 30
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 65,
|
||||||
|
"bonus": 20
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 35,
|
||||||
|
"bonus": 10
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"min_diff": 0,
|
||||||
|
"bonus": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user