Skip to content

Instantly share code, notes, and snippets.

@yangchenyun
Last active April 4, 2024 21:25
Show Gist options
  • Save yangchenyun/6d586b6e1336203d29421563c9612172 to your computer and use it in GitHub Desktop.
Save yangchenyun/6d586b6e1336203d29421563c9612172 to your computer and use it in GitHub Desktop.
Poker_Interview
Display the source blob
Display the rendered blob
Raw
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"<div style=\"text-align: right\"><i>Peter Norvig<br>2012<br>Updated 2020</i></div>\n",
"\n",
"# Poker: Ranking Hands, etc.\n",
"\n",
"\n",
"The [rules for poker hands](https://en.wikipedia.org/wiki/List_of_poker_hands) are complex, but it is an interesting exercise to write a program to rank poker hands.\n",
"\n",
"Some key concepts:\n",
"\n",
"- **Card**: A card will be represented as a two character string, like `'9c'`, where the first character is the **rank** and the second is the **suit**. The ranks are `23456789TJQKA` in ascending order of value and the suits are `'cdhs'` for clubs, diamonds, hearts, and spades; all suits have equal value in poker. \n",
"- **Hand**: A hand is a collection of five cards: `['3s', '3c', 'As', 'Ks', 'Qs']`\n",
"- **Type**: A hand has a ranking type; these are (in highest to lowest order): five of a kind, straight flush, four of a kind, full house, flush, straight, three of a kind, two pair, one pair, high card. (Five of a kind can only be made in games with wild cards.)\n",
"- **Group**: Two or more cards with the same rank: a pair, a three-of-a-kind, etc.\n",
"- **Winning**: If two hands have different types, the higher type wins. If they have the same type, a **tiebreaker** is needed. \n",
"- **Tiebreaker**: For example, the tiebreaker for \"straight\" is the rank of the highest card; a ten-high straight beats a nine-high straight. The tiebreaker for \"three of a kind\" is the rank of the three-of-a-kind group.\n",
"- **Ranking**: To determine which hand wins we could have a comparison function, it is simpler to compare ranks with `ranking(hand) < ranking(hand2)`. The function `ranking` returns a tuple that encompasses the type and tiebreaker. Note that the word **ranking** refers to the value of a *hand*, but **rank** refers to the value of a *card*."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"def ranking(hand) -> tuple:\n",
" \"\"\"Return a (type, tiebreaker) tuple indicating how high the hand ranks.\"\"\"\n",
" pass"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Define main concepts\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Testing Poker Hands\n",
"\n",
"Below is a list of `hands`, with four examples of each **type**, all in descending ranking order (i.e. best to worst). The `test` function asserts that:\n",
"- The `ranking` function agrees with this ordering.\n",
"- The order of cards within a hand does not matter—every permutation of cards is ranked the same. \n",
"- Swapping the suits around (e.g. swapping every spade with every heart) does not change the ranking."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"from itertools import permutations\n",
"cards = str.split # Function to split a string apart into a list of cards\n",
"\n",
"def the_same(things) -> bool: \n",
" \"\"\"Are all the things actually the same?\"\"\"\n",
" return len(set(things)) <= 1\n",
"\n",
"\n",
"hands = [cards(h) for h in ( \n",
" 'As Ks Qs Ts Js', 'Kc Qc Jc Tc 9c', '6d 5d 4d 3d 2d', '5h 4h 3h 2h Ah', # straight flush \n",
" 'As Ac Ad Ah 2s', '7s 7c 7d 2d 7h', '6s 6c 6d 6h 9s', 'As 5h 5c 5d 5s', # four of a kind \n",
" 'Th Tc Td 5h 5c', '9h 9c 9d 8c 8h', '6h 6c 6d Tc Th', '5c 5d 5s As Ah', # full house\n",
" 'As 2s 3s 4s 6s', 'Kc Qc Jc Tc 2c', 'Qc Jc Tc 9c 7c', '4h 5h 6h 7h 9h', # flush\n",
" 'As Kd Qc Td Jh', 'Kc Qh Jd Th 9c', '6c 5d 4h 3s 2s', 'As 2d 3c 4h 5s', # straight\n",
" 'As Ac Ad 2h 3h', 'Ts Tc Th 9s 8c', 'Ts Tc Th 9s 7c', '9h 9s 9d Ah Kh', # three of a kind\n",
" 'Ts Tc 5s 5c 8h', 'Ts Tc 5s 5c 7h', '9s 9c 8s 8c As', '3s 3c 2s 2d Ah', # two pair \n",
" 'As Ac 4c 5s 6s', '4s 4c As Ks Qs', '4h 4d Kh Qd Jd', '2d 2c Ad Kd Qd', # pair \n",
" 'Ah 3s 4s 5s 6s', 'Kh Qh Jh Th 8d', '7d 2s 4s 5s 6s', '7h 6s 5d 3s 2d', # high card\n",
" )]\n",
"\n",
"def test(ranking, hands=hands) -> bool:\n",
" \"\"\"Test that `ranking` preserves order of `hands`, and that permuting cards is irrelevant.\"\"\"\n",
" assert hands == sorted(hands, key=ranking, reverse=True)\n",
" trans = str.maketrans('shdc', 'hscd')\n",
" for hand in hands: \n",
" assert the_same(ranking(h) for h in permutations(hand))\n",
" assert the_same([ranking(hand), ranking([c.translate(trans) for c in hand])])\n",
" return len(hands)"
]
}
],
"metadata": {
"language_info": {
"name": "python"
}
},
"nbformat": 4,
"nbformat_minor": 2
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment