Can I Win: Bitmask Game Theory
Two players take turns picking numbers from a shared pool $\{1, 2, \ldots, M\}$, where $M$ is the max choosable integer. Each number can only be picked once. A running total is kept -- whoever pushes the total to at least $T$ (the desired total) on their turn wins. Both players play optimally.
You go first. Can you guarantee a win?
Constraints:
- \leq M \leq 20$
- $0 \leq T \leq 300$
Examples:
- $M = 10$, $T = 11$: Output
false. No matter what the first player picks, the second player can always counter and reach 11 first. - $M = 10$, $T = 0$: Output
true. The target is already met before anyone moves, so the first player wins immediately. - $M = 4$, $T = 6$: Output
true. First player picks 4, bringing the total to 4. Whatever the second player picks (1, 2, or 3), first player can finish off to reach 6.
Hints
- The order of picks does not matter -- only the SET of numbers already chosen determines the game state. Think about how to encode that set compactly.
- With $M \leq 20$, a bitmask fits the set of chosen numbers in a single integer. The running total is the sum of bits set, so the full state is just the mask -- memoize
can_win(mask)recursively. - Before running the DP, check two edge cases: if $T \leq 0$ return
trueimmediately; if $\sum_{i=1}^{M} i < T$ no one can ever win, returnfalse. Then implement the minimax: current player wins if any choice $i$ either hits the target or forces the opponent into a losing mask.
Worked Solution
How to Think About It: This is a two-player zero-sum combinatorial game with perfect information -- the kind of thing that shows up in algorithmic interviews as a test of whether you recognize the minimax pattern. Brute force means exploring every sequence of picks, which is $M!$ in the worst case -- far too slow for $M = 20$. The key observation: the order in which numbers were picked does not matter, only WHICH numbers have been picked and what the running total is. That collapses the state space dramatically. Since $M \leq 20$, we can represent the set of used numbers as a bitmask of up to 20 bits -- at most
Algorithm:
Define can_win(mask) as: can the player whose turn it is guarantee a win, given that the set of already-chosen numbers is encoded by mask? The running total is implicit -- it is the sum of all bits set in mask. At each state, the current player tries every unchosen number $i$. If choosing $i$ either immediately hits the target (running total + $i \geq T$) or leaves the opponent in a losing state (!can_win(mask | (1 << (i-1)))), then can_win(mask) = true. If no such $i$ exists, can_win(mask) = false.
Two edge cases to handle before the DP: - If $T = 0$, first player wins immediately (target already met). - If the sum of all numbers
false.
Memoize results keyed on the bitmask (the total is determined by the mask, so no extra dimension is needed).
Code:
```python def canIWin(maxChoosableInteger: int, desiredTotal: int) -> bool: if desiredTotal <= 0: return True total_sum = maxChoosableInteger * (maxChoosableInteger + 1) // 2 if total_sum < desiredTotal: return False
memo = {}
def can_win(mask, current_total): if mask in memo: return memo[mask] for i in range(1, maxChoosableInteger + 1): bit = 1 << (i - 1) if mask & bit: continue # already chosen if current_total + i >= desiredTotal: memo[mask] = True return True if not can_win(mask | bit, current_total + i): memo[mask] = True return True memo[mask] = False return False
return can_win(0, 0) ```
Complexity:
- Time: $O(2^M \cdot M)$ -- at most
For $M = 20$: roughly