====== 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 [[:lecture materials/week 05]].
-----
====== Background ======
{{:poker_hand.jpg?nolink|Image of a five-card poker hand, specifically a royal flush with clubs}}
There are [[https://en.wikipedia.org/wiki/List_of_poker_variants|many variants]] game of [[https://en.wikipedia.org/wiki/Pokep|poker]], most of which involve **hands** consisting of five cards from a standard 52-card deck. Hands are [[https://en.wikipedia.org/wiki/List_of_poker_hands|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.
"""
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 ''[[http://jeff.cis.cabrillo.edu/datasets/poker_hands|/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 ''[[https://docs.python.org/3/using/cmdline.html#cmdoption-c|-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"))'
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"))'
-----
====== Submission ======
Submit ''poker_hand.py'' via [[info:turnin]].
{{https://jeff.cis.cabrillo.edu/images/feedback-robot.png?nolink }} //**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|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%
---------------------------------------