"No real interesting mathematical concepts to apply in this one, more just a straight programming problem. Here's a (slightly overengineered) solution.\n",
"\n",
"First we'll define enums for the rank and suit of a card."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "86e737fd",
"metadata": {},
"outputs": [],
"source": [
"from enum import Enum, IntEnum\n",
"\n",
"class Rank(IntEnum):\n",
" TWO = 2\n",
" THREE = 3\n",
" FOUR = 4\n",
" FIVE = 5\n",
" SIX = 6\n",
" SEVEN = 7\n",
" EIGHT = 8\n",
" NINE = 9\n",
" TEN = 10\n",
" JACK = 11\n",
" QUEEN = 12\n",
" KING = 13\n",
" ACE = 14\n",
" \n",
"class Suit(Enum):\n",
" CLUBS = \"C\"\n",
" DIAMONDS = \"D\"\n",
" HEARTS = \"H\"\n",
" SPADES = \"S\""
]
},
{
"cell_type": "markdown",
"id": "b772617e",
"metadata": {},
"source": [
"We'll use these enums to implement a card [dataclass](https://docs.python.org/3/library/dataclasses.html). We define a few comparison methods so we can say what cards rank above others in certain hands. The [total_ordering decorator](https://docs.python.org/3/library/functools.html) defines the comparison methods that are left out. These other methods aren't strictly necessary, but it's a [PEP 8](https://peps.python.org/pep-0008/) recommendation."
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "80ce84b6",
"metadata": {},
"outputs": [],
"source": [
"from dataclasses import dataclass\n",
"from functools import total_ordering\n",
"\n",
"@dataclass\n",
"@total_ordering\n",
"class Card:\n",
" rank: Rank\n",
" suit: Suit\n",
" \n",
" def __init__(self, s):\n",
" x, y = s\n",
" \n",
" lookup = {\n",
" \"2\": Rank.TWO,\n",
" \"3\": Rank.THREE,\n",
" \"4\": Rank.FOUR,\n",
" \"5\": Rank.FIVE,\n",
" \"6\": Rank.SIX,\n",
" \"7\": Rank.SEVEN,\n",
" \"8\": Rank.EIGHT,\n",
" \"9\": Rank.NINE,\n",
" \"T\": Rank.TEN,\n",
" \"J\": Rank.JACK,\n",
" \"Q\": Rank.QUEEN,\n",
" \"K\": Rank.KING,\n",
" \"A\": Rank.ACE,\n",
" }\n",
" self.rank = lookup[x]\n",
" self.suit = Suit(y)\n",
" \n",
" def __eq__(self, other):\n",
" return self.rank == other.rank\n",
" \n",
" def __lt__(self, other):\n",
" return self.rank < other.rank"
]
},
{
"cell_type": "markdown",
"id": "440a49cc",
"metadata": {},
"source": [
"Now we'll make an enum for comparing hand ranks."
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "25fef2a4",
"metadata": {},
"outputs": [],
"source": [
"class HandRank(IntEnum):\n",
" HIGHCARD = 1\n",
" ONEPAIR = 2\n",
" TWOPAIR = 3\n",
" THREEOFAKIND = 4\n",
" STRAIGHT = 5\n",
" FLUSH = 6\n",
" FULLHOUSE = 7\n",
" FOUROFAKIND = 8\n",
" STRAIGHTFLUSH = 9"
]
},
{
"cell_type": "markdown",
"id": "5a1dbf39",
"metadata": {},
"source": [
"Most of the magic happens in the Hand class. We determine a hand's rank with the `rank` method. Then we define comparison methods to determine whether one hand beats another. If two hands have the same rank, we group the cards in each hand by each card's rank, and sort the groups primarily by frequency and secondarily by rank. We then compare these special group orderings to determine which hand wins. This allows for proper handling of situations like example 4 in the problem statement, since it will compare the ranks of the largest groups of cards first - for example, we don't want a pair of kings to lose to a pair of nines just because the latter hand also has an ace."
"This work is licensed under the [Creative Commons Attribution-ShareAlike 4.0 International license](https://creativecommons.org/licenses/by-sa/4.0/) and the [BSD Zero Clause license](https://spdx.org/licenses/0BSD.html)."