cfb40 / scripts /compare_tennessee_plays.py
andytaylor-smg's picture
some decent progress generalizing
137c6cf
#!/usr/bin/env python3
"""Compare Tennessee benchmark vs current FFmpeg output to identify missing plays."""
import json
import logging
from pathlib import Path
logging.basicConfig(level=logging.INFO, format="%(message)s")
logger = logging.getLogger(__name__)
def load_json(path: str) -> dict:
"""Load a JSON file."""
with open(path, "r") as f:
return json.load(f)
def find_matching_play(play: dict, play_list: list, tolerance: float = 2.0) -> dict | None:
"""Find a matching play in the list based on start_time proximity."""
for p in play_list:
if abs(p["start_time"] - play["start_time"]) <= tolerance:
return p
return None
def main():
# Load both outputs
benchmark_path = Path("output/benchmarks/v6_baseline.json")
current_path = Path("output/OSU_vs_Tenn_12_21_24_plays.json")
benchmark = load_json(benchmark_path)
current = load_json(current_path)
benchmark_plays = benchmark["plays"]
current_plays = current["plays"]
logger.info("=" * 80)
logger.info("TENNESSEE PLAY COMPARISON: Benchmark vs FFmpeg")
logger.info("=" * 80)
logger.info(f"\nBenchmark plays: {len(benchmark_plays)}")
logger.info(f"Current plays: {len(current_plays)}")
logger.info(f"Difference: {len(benchmark_plays) - len(current_plays)}")
# Compare play type distributions
logger.info("\n" + "-" * 40)
logger.info("PLAY TYPE COMPARISON")
logger.info("-" * 40)
benchmark_types = benchmark["stats"]["play_types"]
current_types = current["stats"]["play_types"]
logger.info(f"{'Type':<15} {'Benchmark':<12} {'Current':<12} {'Diff':<10}")
for ptype in set(list(benchmark_types.keys()) + list(current_types.keys())):
b_count = benchmark_types.get(ptype, 0)
c_count = current_types.get(ptype, 0)
diff = b_count - c_count
logger.info(f"{ptype:<15} {b_count:<12} {c_count:<12} {diff:+d}")
# Find plays in benchmark that are missing from current
logger.info("\n" + "-" * 40)
logger.info("PLAYS IN BENCHMARK BUT MISSING FROM CURRENT")
logger.info("-" * 40)
missing_plays = []
for bp in benchmark_plays:
match = find_matching_play(bp, current_plays, tolerance=3.0)
if match is None:
missing_plays.append(bp)
logger.info(f"\nFound {len(missing_plays)} missing plays:\n")
for p in missing_plays:
logger.info(f" Play #{p['play_number']:3d}: {p['start_time']:7.1f}s - {p['end_time']:7.1f}s")
logger.info(f" Type: {p['play_type']}, Method: {p['start_method']}")
logger.info(f" Duration: {p['duration']:.1f}s, Clock: {p.get('start_clock_value')} -> {p.get('end_clock_value')}")
logger.info("")
# Group missing plays by type
logger.info("-" * 40)
logger.info("MISSING PLAYS BY TYPE")
logger.info("-" * 40)
missing_by_type = {}
for p in missing_plays:
ptype = p["play_type"]
if ptype not in missing_by_type:
missing_by_type[ptype] = []
missing_by_type[ptype].append(p)
for ptype, plays in sorted(missing_by_type.items()):
logger.info(f"\n{ptype.upper()} plays missing: {len(plays)}")
for p in plays:
logger.info(f" - #{p['play_number']}: {p['start_time']:.1f}s (method: {p['start_method']})")
# Find plays in current that don't exist in benchmark (extra plays)
logger.info("\n" + "-" * 40)
logger.info("PLAYS IN CURRENT BUT NOT IN BENCHMARK (extras)")
logger.info("-" * 40)
extra_plays = []
for cp in current_plays:
match = find_matching_play(cp, benchmark_plays, tolerance=3.0)
if match is None:
extra_plays.append(cp)
if extra_plays:
logger.info(f"\nFound {len(extra_plays)} extra plays:\n")
for p in extra_plays:
logger.info(f" Play #{p['play_number']:3d}: {p['start_time']:7.1f}s - {p['end_time']:7.1f}s")
logger.info(f" Type: {p['play_type']}, Method: {p['start_method']}")
else:
logger.info("\nNo extra plays found (current is a subset of benchmark)")
# Check first play difference - benchmark starts at ~121s, current starts at ~180s
logger.info("\n" + "-" * 40)
logger.info("FIRST FEW PLAYS COMPARISON")
logger.info("-" * 40)
logger.info("\nBenchmark first 5 plays:")
for p in benchmark_plays[:5]:
logger.info(f" #{p['play_number']}: {p['start_time']:.1f}s - {p['play_type']} ({p['start_method']})")
logger.info("\nCurrent first 5 plays:")
for p in current_plays[:5]:
logger.info(f" #{p['play_number']}: {p['start_time']:.1f}s - {p['play_type']} ({p['start_method']})")
if __name__ == "__main__":
main()