\n",
"\n",
"# Properly Organized Card Hands\n",
"\n",
"The 538 Riddler [presented](https://fivethirtyeight.com/features/who-will-capture-the-most-james-bonds/) this problem by [Matt Ginsberg](https://www.linkedin.com/in/matthew-ginsberg-8172bb77/) (slightly rephrased):\n",
" \n",
"> *When you’re dealt a hand of cards, you want to organize them such that (1) the cards of a given suit are grouped together and (2) the suits alternate color (except that if all the cards are the same color, they don't have to alternate). Numbers don’t matter to you, just suits. You want to achieve this proper organization with a single move, relocating one adjacent block of cards to some other position in your hand. What is the probability that you can accomplish your obsessive goal for the game of pitch, which has 6-card hands? What about for any number of cards from 1 and 13?*\n",
"\n",
"Here are four example 6-card hands, two that can be properly organized with a move of a single block (in parens), and two that can't:\n",
"\n",
"|6-card hand|block to move|result of move|properly organized?|\n",
"|---|---|---|---|\n",
"|♠️♥️♦️♣️♣️♦️|♠️♥️♦️(♣️♣️♦️)|♠️♥️(♣️♣️♦️)♦️|yes|\n",
"|♠️♣️♣️♠️♠️♣️|♠️(♣️♣️)♠️♠️♣️|♠️♠️♠️(♣️♣️)♣️|yes; adjacent ♠️♣️ ok because hand is all black|\n",
"|♠️♥️♦️♣️♣️♠️|♠️♥️♦️♣️♣️(♠️)|(♠️)♠️♥️♦️♣️♣️|no; adjacent ♥️♦️ not ok|\n",
"|♠️♥️♠️♥️♠️♥️|♠️♥️(♠️)♥️♠️♥️|♠️♥️♥️(♠️)♠️♥️|no; suits not grouped together|\n",
"\n",
"\n",
"# Brute Force versus Abstraction\n",
"\n",
"The **brute force** approach says: consider every possible hand and check if it is organizable. There are (52 choose *N*) possible *N*-card hands, which is a lot of hands when *N* = 13. The **abstraction** approach asks if there is a way in which one abstract hand can represent multiple concrete hands. It turns out there is: the problem states *\"Numbers don’t matter,\"* so we can abstract from, say, \"seven of spades\" to just \"a spade.\" Then there are only 4*N* abstract hands. Compare:\n",
"\n",
"|*N*|Concrete Hands|Abstract Hands|\n",
"|--|---|---|\n",
"|6|20,358,520|4,096|\n",
"|13|635,013,559,600|67,108,864|\n",
"|*N*|(52 choose *N*) | *N*4|\n",
"\n",
"That's a big improvement! Now let's start designing a program to solve the problem:\n",
"- There are two red suits and two black suits, so I'll represent the four suits as `'rRbB'`.\n",
"- An abstract hand can be represented as a string of suits, for example `'rrBrbr'` is a 6-card hand. \n",
"- The function `deals(N)` will return a [discrete probability distribution](https://en.wikipedia.org/wiki/Probability_distribution) of possible abstract hands of length *N*.\n",
" - For example, `deals(6)` might include the entry `{'rrBrbr': 0.00019}`.\n",
" - With concrete hands, every hand has the same probability, and every card is equally likely to be the next card dealt. But with abstract hands, the probability of the next suit depends on how many cards of that suit have already been dealt. If I've already dealt the 12 cards `'rrrrrrrrrrrr'`, then the probability of the next card being an `'r'` is 1/40, and the probability of it being a `'b'` is 13/40. So as I build up the abstract hands, I'll need to keep track of how many cards of each suit I've already dealt and how many remain.\n",
"- I'll use `fractions.Fraction` to get exact arithmetic and `functools.cache` to avoid repeated computations."
]
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"from fractions import Fraction\n",
"from functools import cache\n",
"from itertools import combinations\n",
"\n",
"type Hand = str # A hand is a string of card suits, like 'rrBBrB'\n",
"type Probability = Fraction"
]
},
{
"cell_type": "code",
"execution_count": 2,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"suits = 'rbRB'\n",
"\n",
"@cache\n",
"def deals(N: int) -> dict[Hand, Probability]:\n",
" \"\"\"A probability distribution of {hand: probability} for all abstract hands of N cards.\"\"\"\n",
" if N == 0: # There is only one zero-card hand: the empty hand.\n",
" return {'': Fraction(1)}\n",
" else: # Every way of adding one card to (N-1)-card hands\n",
" P = deals(N - 1)\n",
" return {hand + suit: P[hand] * (13 - hand.count(suit)) / (52 - len(hand))\n",
" for hand in P\n",
" for suit in suits}"
]
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"data": {
"text/plain": [
"{'r': Fraction(1, 4),\n",
" 'b': Fraction(1, 4),\n",
" 'R': Fraction(1, 4),\n",
" 'B': Fraction(1, 4)}"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"deals(1)"
]
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [
{
"data": {
"text/plain": [
"{'rr': Fraction(1, 17),\n",
" 'rb': Fraction(13, 204),\n",
" 'rR': Fraction(13, 204),\n",
" 'rB': Fraction(13, 204),\n",
" 'br': Fraction(13, 204),\n",
" 'bb': Fraction(1, 17),\n",
" 'bR': Fraction(13, 204),\n",
" 'bB': Fraction(13, 204),\n",
" 'Rr': Fraction(13, 204),\n",
" 'Rb': Fraction(13, 204),\n",
" 'RR': Fraction(1, 17),\n",
" 'RB': Fraction(13, 204),\n",
" 'Br': Fraction(13, 204),\n",
" 'Bb': Fraction(13, 204),\n",
" 'BR': Fraction(13, 204),\n",
" 'BB': Fraction(1, 17)}"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"deals(2)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Is that right? Yes it is. For `deals(1)`, each suit has probability 1/4. For `deals(2)`, the probability of `'BB'` is 1/17, beause the probability of the first `'B'` is 1/4, and when we deal the second card, one `'B'` is gone, so the probability is 12/51, and the product is 1/4 × 12/51 = 1/17. The probability of `'BR'` is 1/4 × 13/51 = 13/204.\n",
"\n",
"# More Abstraction: Collapsed Hands\n",
"\n",
"Now for a second abstraction: a hand can be **collapsed** by replacing a **run** of cards of the same suit with a single card, so that `'BBBBBrrrrBBBB'` collapses to `'BrB'`. We're interested in grouping cards of the same suit together, so for our purposes any number of cards of the same suit is the same as a single card of that suit. "
]
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
"type CollapsedHand = str\n",
"\n",
"def collapse(hand: Hand) -> CollapsedHand:\n",
" \"\"\"Collapse multiple adjacent cards of the same suit into a single card of that suit.\"\"\"\n",
" return ''.join(hand[i] for i in range(len(hand)) if i == 0 or hand[i] != hand[i - 1])"
]
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"assert collapse('BBBBBrrrrBBBB') == 'BrB'"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Properly Organized Hands\n",
"\n",
"A hand is considered properly organized if *\"(1) the cards of a given suit are grouped together and (2) the suits alternate color,\"* with the provision that *\"if the cards are all the same color, they don't have to alternate.\"* In other words: a hand is properly organized if and only if its collapsed hand is properly organized, and a collapsed hand is properly organized if each suit appears only once, and the suits are properly alternating: either all the colors are the same, or suits of the same color don't appear adjacent to each other."
]
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"def organized(hand: Hand) -> bool:\n",
" \"\"\"Properly organized if each suit appears only once, and suits alternate colors.\"\"\"\n",
" hand1 = collapse(hand)\n",
" return once_each(hand1) and alternating_colors(hand1)\n",
"\n",
"colors = str.lower # e.g. colors('RRbbrrBB') == 'rrbbrrbb'\n",
" \n",
"def alternating_colors(hand: CollapsedHand) -> bool: \n",
" \"\"\"Do the colors of suits in the hand alternate (or is there only one color)?\"\"\"\n",
" C = colors(hand)\n",
" return ('bb' not in C and 'rr' not in C) or len(set(C)) == 1\n",
"\n",
"def once_each(hand: CollapsedHand) -> bool: \n",
" \"\"\"Do all the suits in a collapsed hand appear just once each?\"\"\"\n",
" return len(hand) == len(set(hand))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Moving Cards\n",
"\n",
"A hand is organizable if it is already organized or if any of the possible moves of a block of consecutive cards makes the hand organized. I'll throw a `@cache` onto `organizable` so that it won't have to repeat computations."
]
},
{
"cell_type": "code",
"execution_count": 8,
"metadata": {},
"outputs": [],
"source": [
"@cache\n",
"def organizable(hand: CollapsedHand) -> bool: \n",
" \"\"\"Can this collapsed hand be put into proper organize in one move or less?\"\"\"\n",
" return organized(hand) or any(map(organized, moves(hand)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"To find all possible moves, consider every possible start and end position of a block of cards to move, and every possible position to move it too. I'll do that by considering every combination of three index positions (i, j, k) in the hand, with (i < j < k). At first I thought that I would need code for two kinds of moves: moving a block of cards to the right or to the left. But then I realized that if we swap hand[i:j] with hand[j:k], that covers all possible moves: either moving hand[i:j] to the right, or hand[j:k] to the left."
]
},
{
"cell_type": "code",
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
"def moves(hand: Hand) -> set[Hand]:\n",
" \"\"\"All ways of moving a block of cards to get a new hand.\"\"\"\n",
" return {hand[:i] + hand[j:k] + hand[i:j] + hand[k:] # swap hand[i:j] with hand[j:k]\n",
" for (i, j, k) in combinations(range(len(hand) + 1), 3)}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"I'll define `organizable_probability(N)` to give the probability that a random *N*-card hand is organizable. "
]
},
{
"cell_type": "code",
"execution_count": 10,
"metadata": {},
"outputs": [],
"source": [
"def organizable_probability(N: int) -> Probability:\n",
" \"\"\"What's the probability that an N-card hand is organizable?\"\"\"\n",
" P = deals(N)\n",
" return sum(P[hand] for hand in P if organizable(collapse(hand)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Answers for up to 6-Card Hands\n",
"\n",
"Here's the answer for 6 cards:"
]
},
{
"cell_type": "code",
"execution_count": 11,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [
{
"data": {
"text/plain": [
"Fraction(51083, 83895)"
]
},
"execution_count": 11,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"organizable_probability(6) "
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"And an easier-to-read format for everything up to 6 cards:"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Probability that an N-card hand is organizable:\n",
" 0: 100.00% or 1\n",
" 1: 100.00% or 1\n",
" 2: 100.00% or 1\n",
" 3: 100.00% or 1\n",
" 4: 100.00% or 1\n",
" 5: 85.24% or 213019/249900\n",
" 6: 60.89% or 51083/83895\n"
]
}
],
"source": [
"def report(nums: range) -> None:\n",
" \"\"\"Show the probability that an N-card hand is organizable, for each N in nums.\"\"\"\n",
" print('Probability that an N-card hand is organizable:')\n",
" for N in nums:\n",
" P = organizable_probability(N)\n",
" print(f'{N:2}: {float(P):7.2%} or {P}')\n",
" \n",
"report(range(7))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Getting to 13-Card Hands\n",
"\n",
"So far so good, but 413 = 67,108,864 is a big number; `organizable_probability(13)` would take several minutes to run. But I discovered three key properties that can speed things up. These are genral properties that appear in many combinatoric problems:\n",
"\n",
"- **Upper bounds:** We know that a properly organized collapsed hand can have at most 4 characters. But a move can reduce the number of characters by at most 3: one can be reduced when we remove the block of cards (if the cards on either side of the block are the same), and up to two more can be reduced when we re-insert the block (if the left and/or right ends of the block match the surrounding suits). That means that the upper bound on the length of an organizable collapsed hand is 7 characters. Here's an example of moving a block (in parens) to reduce the number of runs from 7 to 4:\n",
"\n",
"|dealt hand|block to move|result of move|properly organized?|\n",
"|---|---|---|---|\n",
"|♥️♣️♦️♠️♥️♣️♠️|♥️♣️♦️♠️(♥️♣️)♠️|♥️(♥️♣️)♣️♦️♠️♠️|yes, collapses to ♥️♣️♦️♠️|\n",
"\n",
" \n",
"- **Monotonicity:** Adding an additional card to an unorganizable collapsed hand can't make it organizable. To see that, take an unorganized collapsed hand, and see what happens if you take the extra card and insert it anywhere in the CollapsedHand. If the CollapsedHand was unorganized because it repeats a suit, adding a suit can't fix that. If it was unorganized because suits of the same color are adjacent, then adding a suit of the other color *could* fix that: `'bBR'` could be fixed by adding an 'r' at the end and moving it to get `'brBR'`. But here's the catch: `'bBR'` is not unorganizable. And if we are going to insert a new suit between two others, that means that the original CollapsedHand must have had at most three suits (because when we add one, we can't get more than four suits in an organized CollapsedHand), and *every* three-suit CollapsedHand is organizable.\n",
"\n",
"- **Symmetry:** Each of the four suits plays the same role in the game; they are symmetric. Thus, for the first card in a hand, we can arbitrarily choose one suit, say 'B', and not consider any of the other suits. Starting with any of the other three suits would give us the same probability, so by only considering 'B' as the first card we get the same answer with 1/4 the computation.\n",
"\n",
"The property of monotonicity means that we can use a strategy where we only keep track of the organizable hands, (not all possible hands), and we stop building onto a hand when it is unorganizable. I'll define `organizable_deals(N)` to return a {hand: probability} dict of just the organizable hands:"
]
},
{
"cell_type": "code",
"execution_count": 13,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"@cache\n",
"def organizable_deals(N: int) -> dict[Hand, Probability]:\n",
" \"\"\"A dict of {hand: probability} for all organizable hands of length N.\"\"\"\n",
" if N == 0: # There is only one zero-card hand: the empty hand.\n",
" return {'': Fraction(1)}\n",
" elif N == 1: # Use symmetry; only consider one suit for first card\n",
" return {'B': Fraction(1)}\n",
" else: # Every way of adding one card to (N-1)-card hands to make organizable hands\n",
" P = organizable_deals(N - 1)\n",
" return {hand + suit: P[hand] * (13 - hand.count(suit)) / (52 - len(hand))\n",
" for hand in P\n",
" for suit in suits\n",
" if organizable(collapse(hand + suit))}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Now I'll redefine `organizable` to take advantage of the 7-character upper bound, and `organizable_probability` to quickly sum the probabilities of the organizable deals:"
]
},
{
"cell_type": "code",
"execution_count": 14,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [],
"source": [
"@cache\n",
"def organizable(hand: CollapsedHand) -> bool: \n",
" \"\"\"Can this collapsed hand be put into proper organize in one move?\"\"\"\n",
" return len(hand) <= 7 and (organized(hand) or any(map(organized, moves(hand))))\n",
"\n",
"def organizable_probability(N: int) -> Probability:\n",
" \"\"\"What's the probability that an N-card hand is organizable?\"\"\"\n",
" return sum(organizable_deals(N).values())"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Final Answer\n",
"\n",
"We're finaly ready to go up to *N* = 13:"
]
},
{
"cell_type": "code",
"execution_count": 15,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [
{
"name": "stdout",
"output_type": "stream",
"text": [
"Probability that an N-card hand is organizable:\n",
" 0: 100.00% or 1\n",
" 1: 100.00% or 1\n",
" 2: 100.00% or 1\n",
" 3: 100.00% or 1\n",
" 4: 100.00% or 1\n",
" 5: 85.24% or 213019/249900\n",
" 6: 60.89% or 51083/83895\n",
" 7: 37.32% or 33606799/90047300\n",
" 8: 20.18% or 29210911/144718875\n",
" 9: 9.86% or 133194539/1350709500\n",
"10: 4.43% or 367755247/8297215500\n",
"11: 1.86% or 22673450197/1219690678500\n",
"12: 0.74% or 1751664923/238130084850\n",
"13: 0.28% or 30785713171/11112737293000\n",
"CPU times: user 491 ms, sys: 6.36 ms, total: 497 ms\n",
"Wall time: 497 ms\n"
]
}
],
"source": [
"%time report(range(14))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Not bad. We got exact answers for all *N* up to 13 in a half second total run time.\n",
"\n",
"# Inspecting the Cache\n",
"\n",
"Let's look at the cache for `organizable(hand)`:"
]
},
{
"cell_type": "code",
"execution_count": 16,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [
{
"data": {
"text/plain": [
"CacheInfo(hits=359627, misses=385, maxsize=None, currsize=385)"
]
},
"execution_count": 16,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"organizable.cache_info()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"So `hhits=359627` menas that that's the number of hands we considered, but only 385 were unique distinct collapsed hands. And once we hit *N* = 7, we've seen all the collapsed hands we're ever going to see. From *N* = 8 and up, almost all the computation goes into computing the probability of each hand, and collapsing each hand, not into deciding which are organizeable.\n",
"\n",
"Now let's look at the number of hands considered by `deals(N)` compared to `organizable_deals(N)`:"
]
},
{
"cell_type": "code",
"execution_count": 17,
"metadata": {},
"outputs": [
{
"data": {
"image/png": "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",
"text/plain": [
""
]
},
"metadata": {},
"output_type": "display_data"
}
],
"source": [
"import matplotlib.pyplot as plt\n",
"\n",
"Ns = range(9)\n",
"plt.plot(Ns, [len(deals(N)) for N in Ns], 'ro-', label='deals(N)')\n",
"Ns = range(14)\n",
"plt.plot(Ns, [len(organizable_deals(N)) for N in Ns], 'bo-', label='organizable_deals(N)')\n",
"plt.grid(True)\n",
"plt.legend();"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The number of deals grows with 4*N*, but the number of organizable deals less than doubles each step; it is growing slower than 2*N*.\n",
"\n",
"# Unit Tests\n",
"\n",
"To gain confidence in this project, here are some unit tests. Before declaring my answers definitively correct, I would want a lot more tests, and some independent code reviews."
]
},
{
"cell_type": "code",
"execution_count": 18,
"metadata": {
"collapsed": false,
"jupyter": {
"outputs_hidden": false
}
},
"outputs": [
{
"data": {
"text/plain": [
"True"
]
},
"execution_count": 18,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"def test():\n",
" assert deals(1) == {'B': 1/4, 'R': 1/4, 'b': 1/4, 'r': 1/4}\n",
" for N in range(7):\n",
" assert len(deals(N)) == 4 ** N # A deal has all 4**N abstract hands\n",
" assert sum(deals(N).values()) == 1 # The sum of the probabilities must be 1.\n",
" assert organizable_deals(1) == {'B': Fraction(1, 1)}\n",
" assert organized('BBBBBrrrrBBBB') is False\n",
" assert organized('BBBBBrrrrRRRR') is False\n",
" assert organized('BBBbbr') is False # Bb\n",
" assert organized('BBBbbrB') is False # two B's\n",
" assert organized('BBBbbb') \n",
" assert organized('BBBbbbB') is False # two B's\n",
" assert organized('BBBBBrrrrbbbb')\n",
" assert organized('BBBbbb')\n",
" assert organized('BBBbbb')\n",
" assert organized('BBBRbb')\n",
" assert organized('BBBbbR') is False\n",
" assert organized('BBBrBB') is False\n",
" assert organized('BBrrBR') is False\n",
" assert colors('BBBBBrrrrbbbb') == 'bbbbbrrrrbbbb'\n",
" assert once_each('Bb')\n",
" assert once_each('BbRr')\n",
" assert once_each('BbRB') is False\n",
" assert alternating_colors('Brb')\n",
" assert alternating_colors('BbR') is False\n",
" assert alternating_colors('BBb')\n",
" assert collapse('BBBBBrrrrBBBB') == 'BrB'\n",
" assert collapse('brBBrrRR') == 'brBrR'\n",
" assert collapse('bbbbBBBrrr') == 'bBr'\n",
" assert moves('bRb') == {'Rbb', 'bbR'}\n",
" assert moves('bRB') == {'BbR', 'RBb', 'RbB', 'bBR'}\n",
" assert organizable('bBr') # move 'r' between 'bB'\n",
" assert organizable('bBrbRBr') # move 'bRB' after first 'b' to get 'bbRBBrr'\n",
" assert organizable('bBrbRBrb') is False\n",
" \n",
" return True\n",
"\n",
"test()"
]
}
],
"metadata": {
"kernelspec": {
"display_name": "Python [conda env:base] *",
"language": "python",
"name": "conda-base-py"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.9"
}
},
"nbformat": 4,
"nbformat_minor": 4
}