"""채점 로직 — docs/SCORING.md (SSOT) 그대로 구현. 배점: 정확 스코어 5 · 근접(승패+득실차) 3 · 승패 2 · 부분(한 팀 득점 일치) 1 · 빗나감 0. 단조 증가(정확>근접>승패>부분>빗나감). 배점 수치는 SCORE 상수만 교체하면 됨. """ from __future__ import annotations # 팀 확정 후 이 상수만 교체 (docs/SCORING.md §2) SCORE = {"EXACT": 5, "CLOSE": 3, "OUTCOME": 2, "PARTIAL": 1, "MISS": 0} def outcome_of(score_a: int, score_b: int) -> str: if score_a > score_b: return "TEAM_A_WIN" if score_a < score_b: return "TEAM_B_WIN" return "DRAW" def score_prediction( pick_a: int, pick_b: int, result_a: int, result_b: int ) -> int: """내 예측 vs 실제 결과 → 적중 포인트 (결정론적).""" if pick_a == result_a and pick_b == result_b: return SCORE["EXACT"] if outcome_of(pick_a, pick_b) == outcome_of(result_a, result_b): if (pick_a - pick_b) == (result_a - result_b): return SCORE["CLOSE"] return SCORE["OUTCOME"] if pick_a == result_a or pick_b == result_b: return SCORE["PARTIAL"] return SCORE["MISS"] # ── 자격 · 배제 (docs/SCORING.md §4, P1 구현) ────────────────── STAFF_EMAILS: set[str] = set() # 운영진/임직원 블록리스트 STAFF_DOMAINS = ["o2o.kr", "aio2o.kr"] def is_excluded(email: str) -> bool: e = email.strip().lower() return e in STAFF_EMAILS or any(e.endswith("@" + d) for d in STAFF_DOMAINS)