User Tools

Site Tools


cs20pf22as05

cs20pf22as05: Poker Hand

Goals

  • Practice with object-oriented design in Python.
  • Define a class that models a card-game object.

Prerequisites

This assignment requires familiarity with the lecture materials presented in class through week 05.


Background

Image of a five-card poker hand, specifically a royal flush with clubs

There are many variants game of poker, most of which involve hands consisting of five cards from a standard 52-card deck. Hands are ranked by category, e.g. straight or two pair.

For the purposes of this assignment, a card descriptor shall be a two-character string consisting of the rank and suit of a card.

Rank characters
23456789TJQKA
Suit characters
♠♣♥♦

Here are ten example card descriptors: T♦ Q♦ 7♥ 3♦ K♠ 2♠ J♣ 2♣ K♥ 2♥


Assignment

You shall define a class named PokerHand in a module named poker_hand. PokerHand instances represent five-card poker hands and support various Python operators for easy interaction with the language, as demonstrated briefly in the REPL session below:

>>> h1 = PokerHand(['4♠', '9♠', '2♣', '2♦', '9♥'])
>>> h1.describe()
'two pair'
>>> int(h1)
2
>>> h2 = PokerHand(['3♠', '3♣', '2♠', 'Q♣', '3♦'])
>>> h2.describe()
'three of a kind'
>>> int(h2)
3
>>> h1 < h2
True
>>> PokerHand(['2♠', '5♠', 'A♥', '4♥', '3♦']) < PokerHand(['Q♠', 'J♠', 'K♣', 'A♠', 'T♥'])
True

Specifications

Define your class with the starter code below, and fill in code for the methods as specified by the docstrings and doctests. Feel free to add other internal-only attributes (module-scoped variables, helper methods, etc.) in order to reduce redundant code.

poker_hand.py
"""
Classifying and ranking poker hands.
 
Numeric ranks and rank descriptions are as follows:
 
0: high card
1: one pair
2: two pair
3: three of a kind
4: straight
5: flush
6: full house
7: four of a kind
8: straight flush
9: royal flush
"""
 
from __future__ import annotations  # for self-referential type hints
from collections.abc import Sequence  # for type hints
 
 
class PokerHand:
  """
  Represents a hand of cards for 5-card poker.
  Card descriptors are two-character strings (RS: Rank and Suit).
  Valid ranks: 23456789TJQKA
  Valid suits: ♥♠♦♣
  """
 
  def __init__(self, cards: Sequence[str]):
    """
    Initializes a poker hand from a sequence of card descriptors.
 
    >>> h = PokerHand(('6♦', 'J♦', '8♣', '4♦', 'T♣'))
    >>> int(h)
    0
    >>> h.describe()
    'high card'
    >>> h2 = PokerHand('6♣ 2♣ 7♣ 5♣ 3♣'.split())
    >>> int(h2)
    5
    >>> h2.describe()
    'flush'
    >>> h < h2
    True
    """
    pass
 
  def __contains__(self, descriptor):
    """
    Determines whether this hand contains the given descriptor.
 
    >>> '2♠' in PokerHand(['3♠', '3♣', '2♠', 'Q♣', '3♦'])
    True
    >>> 'Q♦' in PokerHand(['3♠', '3♣', '2♠', 'Q♣', '3♦'])
    False
    """
    pass
 
  def __int__(self):
    """
    Returns the integer rank for this hand (0 through 9—see class docstring).
 
    >>> hands = ['T♥ A♠ 2♦ 9♣ J♣',
    ...  'T♦ 6♦ 2♠ J♠ T♥',
    ...  '6♣ 5♥ 8♠ 5♠ 6♥',
    ...  '9♠ 9♦ Q♥ 9♥ A♥',
    ...  '7♦ 4♠ 5♦ 6♦ 8♣',
    ...  '5♠ T♠ J♠ 3♠ 2♠',
    ...  'Q♣ 7♣ 7♥ Q♠ Q♦',
    ...  '4♥ 5♣ 5♥ 5♦ 5♠',
    ...  '5♣ 4♣ 8♣ 6♣ 7♣',
    ...  'A♣ J♣ T♣ Q♣ K♣']
    >>> list(map(int, [PokerHand(h.split()) for h in hands]))
    [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
    """
    pass
 
  def __lt__(self, other: PokerHand):
    """Compares this hand with another by rank."""
    pass
 
  def __le__(self, other: PokerHand):
    """Compares this hand with another by rank."""
    pass
 
  def __gt__(self, other: PokerHand):
    """Compares this hand with another by rank."""
    pass
 
  def __ge__(self, other: PokerHand):
    """Compares this hand with another by rank."""
    pass
 
  def __eq__(self, other: PokerHand):
    """Compares this hand with another by rank."""
    pass
 
  def __ne__(self, other: PokerHand):
    """Compares this hand with another by rank."""
    pass
 
  def __repr__(self):
    """Returns a printable representation of this hand, suitable for eval()."""
    pass
 
  def __str__(self):
    """
    Returns the nicely printable string representation of this hand:
    'C1 C2 C3 C4 C5 (rank description)'
 
    >>> h = PokerHand(['7♦', '4♠', '5♦', '6♦', '8♣'])
    >>> print(h)
    7♦ 4♠ 5♦ 6♦ 8♣ (straight)
    """
    pass
 
  def describe(self) -> str:
    """
    Returns the description of this hand's rank (see class docstring).
 
    >>> hands = ['T♥ A♠ 2♦ 9♣ J♣',
    ...  'T♦ 6♦ 2♠ J♠ T♥',
    ...  '6♣ 5♥ 8♠ 5♠ 6♥',
    ...  '9♠ 9♦ Q♥ 9♥ A♥',
    ...  '7♦ 4♠ 5♦ 6♦ 8♣',
    ...  '5♠ T♠ J♠ 3♠ 2♠',
    ...  'Q♣ 7♣ 7♥ Q♠ Q♦',
    ...  '4♥ 5♣ 5♥ 5♦ 5♠',
    ...  '5♣ 4♣ 8♣ 6♣ 7♣',
    ...  'A♣ J♣ T♣ Q♣ K♣']
    >>> list(map(PokerHand.describe, [PokerHand(h.split()) for h in hands]))
    ['high card', 'one pair', 'two pair', 'three of a kind', 'straight', 'flush', 'full house', 'four of a kind', 'straight flush', 'royal flush']
    """
    pass

Test Data

File /srv/datasets/poker_hands contains descriptions and rankings of 1 million sample poker hands, e.g. here are 10 randomly selected lines:

J♦ 2♥ 2♦ 5♠ 9♣ 1
4♦ 8♠ 7♥ 3♣ 4♠ 1
Q♦ 2♠ 7♣ T♠ 4♦ 0
9♠ 3♦ 9♥ 3♥ 7♥ 2
2♥ 5♦ 5♠ 6♥ 2♦ 2
A♣ 4♠ 5♠ 2♦ J♦ 0
3♥ 2♥ 3♣ 3♦ A♠ 3
T♦ 4♠ 4♥ T♥ T♠ 6
4♣ 2♥ A♣ 5♦ A♥ 1
9♠ T♥ 5♦ 2♠ Q♠ 0

If you need some sample hands with a given rank to test/work with, you could either pull them out in a Python script of your own, or use the interpreter as follows with the -c option to quickly isolate the hands you'd like and print them as lists of strings, e.g. to get all straight flush (rank 8) hands in the file:

% python -c 'import sys; print("\n".join(str(t[:-1]) for l in sys.stdin if (t := l.split())[-1] == "8"))' </srv/datasets/poker_hands
['5♣', '4♣', '8♣', '6♣', '7♣']
['T♠', 'J♠', '9♠', '7♠', '8♠']
['4♦', '5♦', '3♦', 'A♦', '2♦']
['7♠', '6♠', '4♠', '5♠', '8♠']
['8♠', '7♠', '5♠', '6♠', '4♠']
['J♣', '7♣', '9♣', 'T♣', '8♣']
['Q♠', 'J♠', 'K♠', '9♠', 'T♠']
['8♥', '7♥', 'J♥', 'T♥', '9♥']
['K♦', 'J♦', 'Q♦', 'T♦', '9♦']
['7♥', '3♥', '6♥', '5♥', '4♥']
['8♥', '7♥', '9♥', '5♥', '6♥']
['T♣', 'Q♣', '9♣', 'J♣', 'K♣']

Or to get 5 randomly selected three-of-a-kind (rank 3) hands:

% python -c 'import sys; print("\n".join(str(t[:-1]) for l in sys.stdin if (t := l.split())[-1] == "3"))' </srv/datasets/poker_hands | shuf -n 5
['K♠', 'K♥', 'K♦', 'A♣', '5♦']
['K♠', 'J♦', 'K♥', 'K♣', '9♠']
['6♦', 'J♣', '3♦', '6♠', '6♣']
['3♦', '3♠', 'T♠', '6♥', '3♣']
['T♥', '6♥', 'T♠', '4♦', 'T♦']

Submission

Submit poker_hand.py via turnin.

Feedback Robot

This project has a feedback robot that will run some tests on your submission and provide you with a feedback report via email within roughly one minute.

Please read the feedback carefully.

Due Date and Point Value

Due at 23:59:59 on the date listed on the syllabus.

Assignment 05 is worth 60 points.

Possible point values per category:
---------------------------------------
Hand comparison methods              36
Other methods                        24
Possible deductions:
  Style and practices            10–20%
Possible extra credit:
  Submission via Git                 5%
---------------------------------------
cs20pf22as05.txt · Last modified: 2023-08-17 10:43 by 127.0.0.1