""" core/checker.py --------------- Ticket checker — compare a user-supplied ticket against all historical draws. Returns every draw where at least one number (main or bonus) matched, sorted by match quality descending. Prize tiers follow Powerball / Mega Millions conventions: Jackpot 5 main + bonus Match 5 5 main, no bonus Match 4 + Bonus 4 main + bonus Match 4 4 main Match 3 + Bonus 3 main + bonus Match 3 3 main Match 2 + Bonus 2 main + bonus Match 1 + Bonus 1 main + bonus Bonus Only 0 main + bonus """ from db.models import get_all_draws_numbers, get_game_by_id # (required_main_matches, requires_bonus_match, tier_label) _TIERS = [ (5, True, "Jackpot"), (5, False, "Match 5"), (4, True, "Match 4 + Bonus"), (4, False, "Match 4"), (3, True, "Match 3 + Bonus"), (3, False, "Match 3"), (2, True, "Match 2 + Bonus"), (1, True, "Match 1 + Bonus"), (0, True, "Bonus Only"), ] def prize_tier(main_matches: int, bonus_match: bool) -> str: """Return the prize tier label for a given match result.""" for req_main, req_bonus, label in _TIERS: if main_matches == req_main: if req_bonus and not bonus_match: continue return label return "No Prize" def check_ticket(game_id: int, numbers: list[int], bonus: int | None = None) -> list[dict]: """ Compare *numbers* (and optional *bonus*) against all draws for *game_id*. Returns a list of dicts for draws with ≥ 1 matched number (main or bonus), sorted by (main_matches DESC, bonus_match DESC, draw_date DESC). Each dict contains: draw_date str draw_numbers list[int] draw_bonus int | None main_matches int bonus_match bool prize_tier str """ draws = get_all_draws_numbers(game_id) ticket_set = set(numbers) results = [] for draw in draws: draw_set = set(draw["numbers"]) main_matches = len(ticket_set & draw_set) bonus_match = ( bonus is not None and draw["bonus"] is not None and bonus == draw["bonus"] ) if main_matches == 0 and not bonus_match: continue results.append({ "draw_date": draw["draw_date"], "draw_numbers": draw["numbers"], "draw_bonus": draw["bonus"], "main_matches": main_matches, "bonus_match": bonus_match, "prize_tier": prize_tier(main_matches, bonus_match), }) results.sort( key=lambda x: (x["main_matches"], x["bonus_match"], x["draw_date"]), reverse=True, ) return results def parse_numbers(raw: str) -> list[int]: """ Parse a user-typed string of lottery numbers into a sorted list of ints. Accepts space- or comma-separated input: '7 14 32 56 68' or '7,14,32,56,68'. Raises ValueError if any token is not a positive integer. """ tokens = raw.replace(",", " ").split() if not tokens: raise ValueError("No numbers entered.") nums = [] for t in tokens: if not t.isdigit(): raise ValueError(f"'{t}' is not a valid number.") nums.append(int(t)) return sorted(nums)