""" core/wheeling.py ---------------- Full-cover number wheeling. wheel_count(numbers, k) — C(n, k) ticket count preview wheel_full(numbers, k) — all C(n, k) sorted combinations Raises ValueError for invalid inputs or if result exceeds MAX_TICKETS. """ from itertools import combinations from math import comb MAX_TICKETS = 200 def wheel_count(numbers: list | set, k: int) -> int: """Return how many tickets a full wheel would produce (C(n, k)).""" n = len(set(numbers)) if k < 1 or k > n: return 0 return comb(n, k) def wheel_full(numbers: list | set, k: int) -> list[list[int]]: """ Generate all C(n, k) combinations from *numbers*, each sorted ascending. Duplicates in input are removed before wheeling. Raises ValueError if k is out of range or count > MAX_TICKETS. """ pool = sorted(set(numbers)) n = len(pool) if k < 1: raise ValueError("Pick count must be at least 1.") if k > n: raise ValueError( f"Pick count ({k}) exceeds the number pool size ({n})." ) count = comb(n, k) if count > MAX_TICKETS: raise ValueError( f"Wheel would produce {count:,} tickets (max {MAX_TICKETS:,}). " f"Reduce your pool or pick count." ) return [sorted(combo) for combo in combinations(pool, k)]