Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import csv
- import glob
- import json
- import os
- import subprocess
- import sys
- import time
- BASE_DIR = os.path.dirname(os.path.abspath(__file__))
- HARNESS = os.path.join(BASE_DIR, "fm24ctl.exe")
- FIXTURES_DIR = os.path.join(BASE_DIR, "fixtures")
- RESULTS_DIR = os.path.join(BASE_DIR, "resultats")
- TEMP_DIR = os.path.join(BASE_DIR, "temp")
- for d in [FIXTURES_DIR, RESULTS_DIR, TEMP_DIR]:
- os.makedirs(d, exist_ok=True)
- # THE 3 FIXTURES OF THE "GOLDEN TRIPTYCH"
- FIXTURES = [
- {"name": "Crystal Palace (Median)", "file": os.path.join(FIXTURES_DIR, "aston-villa-v-crystal-palace-1792853408.json")},
- {"name": "Man City (Elite)", "file": os.path.join(FIXTURES_DIR, "astonvscity.json")},
- {"name": "Luton Town (Low Block)", "file": os.path.join(FIXTURES_DIR, "astonvsluton.json")}
- ]
- TEMP_JSON = os.path.join(TEMP_DIR, "temp_fixture_strict.json")
- CSV_OUT = os.path.join(TEMP_DIR, "temp_sim_out_strict.csv")
- # Existing unified output files to be enriched
- OUTPUT_JSON_SEGMENTS = os.path.join(RESULTS_DIR, "mes_segments_overnight.json")
- OUTPUT_GLOBAL_CSV = os.path.join(RESULTS_DIR, "bilan_general_overnight.csv")
- # HIGH PRECISION (500 matches per tier x 3 fixtures = 1,500 matches per tier)
- MATCHES_PER_LEVEL = 500
- TIERS = [1, 8, 12, 16, 20]
- # Personality attributes (Stored under home.player[X].personality.[attr], direct 1-20 scale)
- PERSONALITY_ATTRIBUTES = {
- "sportsmanship", "professionalism", "loyalty", "temperament",
- "pressure", "ambition", "adaptability", "controversy"
- }
- # 1. REMAINING ATTRIBUTES FOR OUTFIELD PLAYERS
- REMAINING_OUTFIELD_ATTRIBUTES = [
- "marking", "corners", "free_kicks", "long_throws", "penalty_taking",
- "flair", "off_the_ball",
- "consistency", "important_matches", "injury_proneness",
- "pressure", "professionalism", "ambition", "loyalty",
- "temperament", "sportsmanship", "adaptability"
- ]
- # 2. REMAINING ATTRIBUTES FOR GOALKEEPERS
- REMAINING_GK_ATTRIBUTES = [
- "dirtiness", "first_touch", "passing", "technique", "throwing",
- "flair", "off_the_ball",
- "consistency", "important_matches", "injury_proneness",
- "pressure", "professionalism", "ambition", "loyalty",
- "temperament", "sportsmanship", "adaptability"
- ]
- # Combined queue: (Attribute, is_gk)
- QUEUE_COMPLEMENT = [(attr, False) for attr in REMAINING_OUTFIELD_ATTRIBUTES] + [(attr, True) for attr in REMAINING_GK_ATTRIBUTES]
- def cleanup():
- """Remove temporary binary job files left by the harness."""
- for f in glob.glob(os.path.join(BASE_DIR, "_job_input*.bin")):
- try:
- os.remove(f)
- except OSError:
- pass
- def simulate(fixture_path, attr_name, val_out_of_20, is_gk):
- """Run batch simulation for a fixture, attribute value, and player target."""
- targets = [0] if is_gk else list(range(1, 11))
- is_personality = attr_name in PERSONALITY_ATTRIBUTES
- if is_personality:
- val_fm = int(val_out_of_20) # Direct 1-20 scale
- target_names = {f"home.player[{idx}].personality.{attr_name}" for idx in targets}
- else:
- val_fm = int(val_out_of_20 * 5) # 1-100 scale for u8map
- target_names = {f"home.player[{idx}].ratings" for idx in targets}
- with open(fixture_path, "r", encoding="utf-8") as f:
- data = json.load(f)
- entries = data.get("fields", []) if isinstance(data, dict) else data
- modified_count = 0
- for entry in entries:
- if isinstance(entry, dict):
- name = entry.get("name")
- if is_personality:
- if name in target_names and "u8" in entry:
- entry["u8"] = val_fm
- modified_count += 1
- else:
- if name in target_names:
- u8map = entry.get("u8map", {})
- if attr_name in u8map:
- u8map[attr_name] = val_fm
- modified_count += 1
- if modified_count == 0:
- return None # Attribute missing from file for this target, gracefully ignored
- with open(TEMP_JSON, "w", encoding="utf-8") as f:
- json.dump(data, f)
- cmd = [HARNESS, "run", TEMP_JSON, f"1-{MATCHES_PER_LEVEL}", CSV_OUT, "--keep-build"]
- subprocess.run(cmd, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
- csv_res = CSV_OUT if os.path.exists(CSV_OUT) else TEMP_JSON.replace(".json", ".csv")
- gd = 0.0
- if os.path.exists(csv_res):
- with open(csv_res, "r", encoding="utf-8") as f:
- reader = csv.DictReader(f)
- for row in reader:
- gd += (int(row["home_goals"]) - int(row["away_goals"]))
- try:
- os.remove(csv_res)
- except OSError:
- pass
- cleanup()
- return gd / MATCHES_PER_LEVEL
- def test_full_attribute(attr_name, is_gk):
- """Evaluate performance deltas across all tiers."""
- tier_means = {}
- for p in TIERS:
- gd_total = 0.0
- for fix in FIXTURES:
- gd = simulate(fix["file"], attr_name, p, is_gk)
- if gd is None:
- return None # Attribute not found in data, aborting this test
- gd_total += gd
- tier_means[p] = gd_total / len(FIXTURES)
- base_gd = tier_means[8]
- deltas = {p: (tier_means[p] - base_gd) * 38 for p in TIERS}
- segments = [
- {"from": 16, "to": 20, "pts": round(deltas[20] - deltas[16], 1)},
- {"from": 12, "to": 16, "pts": round(deltas[16] - deltas[12], 1)},
- {"from": 8, "to": 12, "pts": round(deltas[12] - deltas[8], 1)},
- {"from": 1, "to": 8, "pts": round(deltas[8] - deltas[1], 1)}
- ]
- amplitude = round(deltas[20] - deltas[1], 1)
- return deltas, segments, amplitude
- def enrich_results(attr_name, is_gk, deltas, segments, amplitude):
- """Append calibrated segments to JSON and add stats to CSV."""
- key_camel = "".join(x.capitalize() for x in attr_name.split("_"))
- # 1. Update existing JSON structure
- structure = {"position_weights": {"GK": {}, "OUTFIELD": {}}}
- if os.path.exists(OUTPUT_JSON_SEGMENTS):
- try:
- with open(OUTPUT_JSON_SEGMENTS, "r", encoding="utf-8") as f:
- structure = json.load(f)
- except Exception:
- pass
- if "position_weights" not in structure:
- structure["position_weights"] = {"GK": {}, "OUTFIELD": {}}
- section = "GK" if is_gk else "OUTFIELD"
- structure["position_weights"][section][key_camel] = segments
- with open(OUTPUT_JSON_SEGMENTS, "w", encoding="utf-8") as f:
- json.dump(structure, f, indent=2)
- # 2. Append to existing CSV summary
- file_exists = os.path.exists(OUTPUT_GLOBAL_CSV)
- with open(OUTPUT_GLOBAL_CSV, "a", newline="", encoding="utf-8") as f:
- writer = csv.writer(f)
- if not file_exists:
- writer.writerow(["Attribute", "Target", "P1", "P8 (0.0)", "P12", "P16", "P20", "Triangulated_38m_Amplitude"])
- writer.writerow([
- attr_name, "Goalkeeper" if is_gk else "Outfield",
- f"{deltas[1]:+.1f}", "0.0", f"{deltas[12]:+.1f}", f"{deltas[16]:+.1f}", f"{deltas[20]:+.1f}", f"{amplitude:+.1f}"
- ])
- def main():
- total = len(QUEUE_COMPLEMENT)
- print("\n=======================================================")
- print(" STRICT COMPLEMENTARY BENCHMARK (OUTFIELD + GOALKEEPER)")
- print(f" {total} tests scheduled | {MATCHES_PER_LEVEL} matches/tier")
- print(f" Automatic injection into: {OUTPUT_JSON_SEGMENTS}")
- print("=======================================================\n")
- for fix in FIXTURES:
- if not os.path.exists(fix["file"]):
- print(f"[ERROR] File not found: {fix['file']}")
- return
- t0_global = time.time()
- for idx, (attr, is_gk) in enumerate(QUEUE_COMPLEMENT, 1):
- t0 = time.time()
- target_label = "GOALKEEPER (P0)" if is_gk else "OUTFIELD (P1-10)"
- print(f"[{idx:2d}/{total}] {attr.upper()} ({target_label})...", end="", flush=True)
- result = test_full_attribute(attr, is_gk)
- if result is None:
- print(" SKIPPED (Missing from JSON data)")
- continue
- deltas, segments, amp = result
- enrich_results(attr, is_gk, deltas, segments, amp)
- print(f" OK ({time.time() - t0:.1f}s) | Impact: {amp:+.1f} pts")
- print("\n=======================================================")
- print(f" COMPLETION FINISHED IN {(time.time() - t0_global) / 3600:.2f} HOURS!")
- print(" -> Master files enriched successfully!")
- print("=======================================================")
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment