Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import csv
- import glob
- import json
- import math
- 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)
- 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)", "file": os.path.join(FIXTURES_DIR, "astonvsluton.json")}
- ]
- TEMP_JSON = os.path.join(TEMP_DIR, "temp_fixture_stable.json")
- CSV_OUT = os.path.join(TEMP_DIR, "temp_sim_out_stable.csv")
- OUTPUT_JSON_SEGMENTS = os.path.join(RESULTS_DIR, "segments_calibres_fmss.json")
- OUTPUT_GLOBAL_CSV = os.path.join(RESULTS_DIR, "bilan_statistique_hp.csv")
- # 1,500 matches x 3 = 4,500 matches per level (22,500 / attr) -> ~1h per attribute
- MATCHES_PER_LEVEL = 1500
- TIERS = [1, 8, 12, 16, 20]
- # OUTFIELD PLAYERS QUEUE
- ACTIVE_QUEUE = [
- ("reflexes", True),
- ("agility", True),
- ("aerial_reach", True),
- ("command_of_area", True),
- ("handling", True),
- ("one_on_ones", True),
- ("positioning", True),
- ("pace", False),
- ("acceleration", False),
- ("jumping_reach", False),
- ("work_rate", False),
- ("dribbling", False),
- ("tackling", False),
- ("passing", False),
- ("finishing", False),
- ("stamina", False),
- ("balance", False),
- ("anticipation", False),
- ("concentration", False)
- ]
- def cleanup():
- """Remove temporary binary job files left behind 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 simulation batch for a given fixture, attribute value, and player target."""
- val_fm = int(val_out_of_20 * 5)
- raw_attr = attr_name[3:] if attr_name.startswith("gk_") else attr_name
- with open(fixture_path, "r", encoding="utf-8") as f:
- data = json.load(f)
- entries = data.get("fields", []) if isinstance(data, dict) else data
- targets = [0] if is_gk else list(range(1, 11))
- target_names = {f"home.player[{idx}].ratings" for idx in targets}
- modified_count = 0
- for entry in entries:
- if isinstance(entry, dict) and entry.get("name") in target_names:
- u8map = entry.get("u8map", {})
- if raw_attr in u8map:
- u8map[raw_attr] = val_fm
- modified_count += 1
- if modified_count == 0:
- return 0.0, 0.0
- 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")
- gds = []
- if os.path.exists(csv_res):
- with open(csv_res, "r", encoding="utf-8") as f:
- reader = csv.DictReader(f)
- for row in reader:
- gds.append(int(row["home_goals"]) - int(row["away_goals"]))
- try:
- os.remove(csv_res)
- except OSError:
- pass
- cleanup()
- if not gds:
- return 0.0, 0.0
- mean_gd = sum(gds) / len(gds)
- variance = sum((x - mean_gd) ** 2 for x in gds) / len(gds)
- std_err = math.sqrt(variance / len(gds))
- return mean_gd, std_err
- def test_attribute(attr_name, is_gk):
- """Evaluate performance across all defined tiers and compute confidence intervals."""
- tier_means = {}
- tier_errors = {}
- for p in TIERS:
- t_tier = time.time()
- gd_tot = 0.0
- err_sq_tot = 0.0
- for fix in FIXTURES:
- gd, s_err = simulate(fix["file"], attr_name, p, is_gk)
- gd_tot += gd
- err_sq_tot += s_err ** 2
- tier_means[p] = gd_tot / len(FIXTURES)
- tier_errors[p] = math.sqrt(err_sq_tot) / len(FIXTURES)
- print(f" [P{p}: {(time.time() - t_tier) / 60:.1f}m]", end="", flush=True)
- base_gd = tier_means[8]
- deltas = {p: (tier_means[p] - base_gd) * 38 for p in TIERS}
- ci_95 = {p: (tier_errors[p] * 1.96) * 38 for p in TIERS}
- segments = [
- {"from": 16, "to": 20, "pts": round(deltas[20] - deltas[16], 2)},
- {"from": 12, "to": 16, "pts": round(deltas[16] - deltas[12], 2)},
- {"from": 8, "to": 12, "pts": round(deltas[12] - deltas[8], 2)},
- {"from": 1, "to": 8, "pts": round(deltas[8] - deltas[1], 2)}
- ]
- amplitude = round(deltas[20] - deltas[1], 2)
- return deltas, ci_95, segments, amplitude
- def save_results(attr_name, is_gk, deltas, ci_95, segments, amplitude):
- """Save calibrated segments to JSON and append statistical summary to CSV."""
- key_camel = "".join(x.capitalize() for x in attr_name.split("_"))
- 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
- 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)
- 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", "P12", "P16", "P20", "Amplitude_38m", "CI95_Margin"])
- writer.writerow([
- attr_name, "Goalkeeper" if is_gk else "Outfield",
- f"{deltas[1]:+.2f}", "0.0", f"{deltas[12]:+.2f}", f"{deltas[16]:+.2f}", f"{deltas[20]:+.2f}",
- f"{amplitude:+.2f}", f"±{ci_95[20]:.2f} pts"
- ])
- def main():
- total = len(ACTIVE_QUEUE)
- print("=" * 65)
- print(f" SAFE SEQUENTIAL BENCHMARK (N = {MATCHES_PER_LEVEL * 3} matches / tier)")
- print(" Estimated throughput: ~1h per attribute | No DLL conflict risk")
- print("=" * 65)
- t0_global = time.time()
- for idx, (attr, is_gk) in enumerate(ACTIVE_QUEUE, 1):
- t0 = time.time()
- target_str = "GK" if is_gk else "OUTFIELD"
- print(f"\n[{idx}/{total}] {attr.upper()} ({target_str})...", end="", flush=True)
- deltas, ci_95, segments, amp = test_attribute(attr, is_gk)
- save_results(attr, is_gk, deltas, ci_95, segments, amp)
- duration = (time.time() - t0) / 60
- print(f"\n -> Validated in {duration:.1f} min | Amplitude: {amp:+.2f} pts (CI95: ±{ci_95[20]:.2f})")
- print("\n" + "=" * 65)
- print(f" SESSION COMPLETED IN {(time.time() - t0_global) / 3600:.2f} HOURS")
- print("=" * 65)
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment