Library · The Fiddler: Solutions · Chapter 140
Can You Throw the Card Game?
The card game Slap is played by two players, each dealt cards from a standard deck. They take turns putting down one card at a time on a shared pile.
If a player puts down a jack, the other player must put down one card, and a face card among them passes the challenge back; if none comes, the first player wins the round and collects the pile. A queen gives the other player up to two chances to answer with a face card, a king three, and an ace four. (Here, as in the game, “face card” means jack, queen, king or ace.)
Whenever two cards of the same rank are played one after the other in the same round, either player can slap the pile and win the round.
The round’s winner puts the pile under their own cards, the last card played at the very bottom, and leads the next round.
To keep a sore loser happy, the puzzle’s author rigged the deal so that the opponent held a majority of the jacks, of the queens, of the kings and of the aces. Caught out, the author claims this happens by chance often enough. With a fair deal, what is the probability that the opponent receives at least three of each of the four kinds of face card?
The Fiddler, Zach Wissner-Gross, October 13, 2023(original post)
The official solution appeared in the post of October 20, 2023 and gives percent for the main puzzle, which agrees with the answer below. For the Extra Credit the official reports only simulations by solvers, all “around percent”; the value below is from my own simulation and is consistent with that.
Solution
The opponent’s hand is a random set of of the cards, every such set equally likely, so the probability is a count of good hands divided by .
A good hand has three or four of each face. Sort the good hands by , the number of faces of which the opponent has all four. Then:
the complete faces can be chosen in ways;
each of the other faces is missing exactly one of its four cards, chosen in ways, giving ;
the hand then holds face cards, so its other cards come from the number cards, in ways.
| product | |||
|---|---|---|---|
| total |
Dividing by and cancelling, About one fair deal in , so the author’s defence does not hold up. (If either player holding all four majorities counts, the chance doubles to about .) Even one face is less likely than it looks: the chance of holding all four jacks is , a little under , because each jack dealt to the opponent leaves less room in the hand for the next.
The computation
The check deals hands at random, times, and counts how often the opponent’s cards include at least three of each face. Ranks run from to , with to the jack, queen, king and ace.
import random
from collections import Counter, deque
DECK = [rank for rank in range(2, 15) for _ in range(4)]
FACES = {11: 1, 12: 2, 13: 3, 14: 4} # J Q K A: chances owed
rng = random.Random(2023)
def majority_of_every_face(hand):
held = Counter(hand)
return all(held[face] >= 3 for face in FACES)
deals = 1_500_000
hits = sum(majority_of_every_face(rng.sample(DECK, 26))
for _ in range(deals))
p = hits / deals
print(f"main: {p:.5f} +/- {(p * (1 - p) / deals) ** 0.5:.5f}")
It prints the estimate and its standard error,
main: 0.00348 +/- 0.00005
within about one and a half standard errors of the exact .
Extra Credit
Rigging the deal is hard, so instead the author deals fairly but always loses every slap to the opponent, who also plays the first card. What is the author’s probability of winning the game?
Solution
There is no tidy formula here: the game is a long deterministic process driven by the shuffle, and its outcome has to be found by playing it. What the solution can do is fix the rules precisely, since the post leaves a few details open, and then simulate. The rules used are these.
The opponent leads the first round. Players alternate until a face card is played; from then on the challenged player keeps playing until they either answer with a face card, which starts a new challenge against the other player, or use up their chances, in which case the challenger wins the round.
The moment the top two cards of the pile have the same rank, the round ends and the opponent takes the pile, whoever played those cards. The opponent always notices and always wins the slap.
The winner of a round puts the pile, in the order played, under their own cards, and leads the next round.
A player who has to play a card and has none left loses the game.
Slaps are frequent: in a long round, a double turns up often, and every one of them goes to the opponent. The author wins only by taking rounds on face-card challenges fast enough to strip the opponent of cards first. A simulation of games under these rules gives with a standard error of about percentage points. Every game ended; none cycled forever. The solvers quoted in the official write-up, playing by their own readings of the rules, all reported about percent.
The computation
The game is simulated card by card, using the deck and random generator from The computation above. Each round tracks who led, who is owed a face card and how many chances remain, and ends on a slap or a failed challenge.
def play(rng, cap=100_000):
"""One game; player 0 is the opponent (leads first and
wins every slap), player 1 is me. Returns the winner,
or None if the game is still going after cap cards."""
deck = DECK[:]
rng.shuffle(deck)
hands = [deque(deck[:26]), deque(deck[26:])]
leader, played = 0, 0
while True:
pile, player, owed, challenger = [], leader, 0, None
while True:
if not hands[player]:
return 1 - player # cannot play: loses
card = hands[player].popleft()
pile.append(card)
played += 1
if played > cap:
return None
if len(pile) >= 2 and pile[-1] == pile[-2]:
winner = 0 # opponent slaps first
elif card in FACES: # a new challenge
challenger, owed = player, FACES[card]
player = 1 - player
continue
elif challenger is None: # ordinary play
player = 1 - player
continue
else: # failed answer
owed -= 1
if owed:
continue
winner = challenger
hands[winner].extend(pile) # last card at bottom
leader = winner
break
games = 200_000
results = Counter(play(rng) for _ in range(games))
p = results[1] / games
err = (p * (1 - p) / games) ** 0.5
print(f"extra credit: {p:.4f} +/- {err:.4f}")
print("games unfinished:", results[None])
It prints
extra credit: 0.0405 +/- 0.0004
games unfinished: 0