STAT 19000: Project 11 — Spring 2022
Motivation: We’d be remiss spending almost an entire semester solving data driven problems in python without covering the basics of classes. Whether or not you will ever choose to use this feature in your work, it is best to at least understand some of the basics so you can navigate libraries and other code that does use it.
Context: We’ve spent nearly the entire semester solving data driven problems using Python, and now we are going to learn about one of the primary features in Python: classes. Python is an object oriented programming language, and as such, much of Python, and the libraries you use in Python are objects which have attributes and methods. In this project we will explore some of the terminology and syntax relating to classes. This is the second in a series of 3 projects focused on reading and writing classes in Python.
Scope: Python, classes
Questions
Question 1
from collections import Counter
class Player:
def __init__(self, name, deck):
self.name = name
self.deck = deck
self.hand = []
def __str__(self):
return(f"""
{self.name}\n
Top 5 cards: {self.deck[:5]}
""")
def draw(self):
card = self.deck.cards.pop(0)
self.hand.append(card)
def has_set(self):
summarizedhand = Counter(self.hand)
for key, value in summarizedhand.items():
if value >= 3:
return True
return False
class Card:
_value_dict = {"2": 2, "3": 3, "4": 4, "5": 5, "6": 6, "7": 7, "8":8, "9":9, "10": 10, "j": 11, "q": 12, "k": 13, "a": 14}
def __init__(self, number, suit):
if str(number).lower() not in [str(num) for num in range(2, 11)] + list("jqka"):
raise Exception("Number wasn't 2-10 or J, Q, K, or A.")
else:
self.number = str(number).lower()
if suit.lower() not in ["clubs", "hearts", "diamonds", "spades"]:
raise Exception("Suit wasn't one of: clubs, hearts, spades, or diamonds.")
else:
self.suit = suit.lower()
def __str__(self):
return(f'{self.number} of {self.suit.lower()}')
def __repr__(self):
return(f'Card(str({self.number}), "{self.suit}")')
def __eq__(self, other):
if self.number == other.number:
return True
else:
return False
def __lt__(self, other):
if self._value_dict[self.number] < self._value_dict[other.number]:
return True
else:
return False
def __gt__(self, other):
if self._value_dict[self.number] > self._value_dict[other.number]:
return True
else:
return False
def __hash__(self):
return hash(self.number)
class Deck:
brand = "Bicycle"
_suits = ["clubs", "hearts", "diamonds", "spades"]
_numbers = [str(num) for num in range(2, 11)] + list("jqka")
def __init__(self):
self.cards = [Card(number, suit) for suit in self._suits for number in self._numbers]
def __len__(self):
return len(self.cards)
def __getitem__(self, key):
return self.cards[key]
def __setitem__(self, key, value):
self.cards[key] = value
def __str__(self):
return f"A {self.brand.lower()} deck."
Recall from the previous project the following.
Two common patterns that are important to be able to quickly recognize in many gin rummy games are sets and runs.
A set is a group of cards with different suits but the same value. In order to qualify as a set, there must be 3 or more cards.
A run is a group of cards with the same suit with sequential values. In order to qualify as a run, there must be 3 or more cards.
In the final question from the previous project we wrote a method (a function for a class) called has_set
which returned True
if the given Player
had a set or not. This is useful, sure, but not as useful as it could be!
Write another method called get_sets
which returns a list of lists, where each nested list contains the cards of a complete set. The results should look something like the following, feel free to run the code many times to see if it looks as if it is working.
import random
deck = Deck()
player1 = Player("Alice", deck)
random.shuffle(deck)
for _ in range(20):
player1.draw()
sets = player1.get_sets()
sets
[[Card(str(5), "clubs"), Card(str(5), "spades"), Card(str(5), "hearts")], [Card(str(6), "diamonds"), Card(str(6), "clubs"), Card(str(6), "spades")]]
-
Code used to solve this problem.
-
Output from running the code.
Question 2
Runs are a bit more complicated to figure out than sets. In order to make things slightly easier, let’s write a method called hand_as_df
that takes a player’s hand and converts it into a pandas dataframe with the following columns: suit
, numeric_value
, card
. The first column is just a column with the strings: "spades", "hearts", "diamonds", or "clubs". The second is the numeric value of a given card: 1 through 13.
You may want to change your |
The final column is the Card
object itself!
The following should result in a dataframe.
import random
deck = Deck()
player1 = Player("Alice", deck)
random.shuffle(deck)
for _ in range(20):
player1.draw()
sets = player1.hand_as_df()
sets
-
Code used to solve this problem.
-
Output from running the code.
Question 3
Okay, now for the more challenging part. Write a method called get_runs
that returns a list of lists where each list contains the cards of the given run. Note that runs of more than 3 should be in the same list. If a run is 6 or more, it should be represented in a single list, not 2 lists of 3 or more.
You can run the following code until you can see that your method is working as intended.
import random
deck = Deck()
player1 = Player("Alice", deck)
random.shuffle(deck)
for _ in range(20):
player1.draw()
runs = player1.get_runs()
runs
[[Card(str(j), "hearts"), Card(str(q), "hearts"), Card(str(k), "hearts")], [Card(str(a), "spades"), Card(str(2), "spades"), Card(str(3), "spades"), Card(str(4), "spades"), Card(str(5), "spades")]]
Since this question is more challenging than normal, this is the last question. Try to solve this puzzle before looking at the tips below!
Grouping by To group by suit and loop through the groups, you can use the
|
Think about the following values. Consider the values
some_column, numeric_value, difference 1, 1, 0 2, 2, 0 3, 3, 0 4, 5, -1 5, 6, -1 6, 8, -2 7, 9, -2 7, 9, -2 |
-
Code used to solve this problem.
-
Output from running the code.
Please make sure to double check that your submission is complete, and contains all of your code and output before submitting. If you are on a spotty internet connect ion, it is recommended to download your submission after submitting it to make sure what you think you submitted, was what you actually submitted. In addition, please review our submission guidelines before submitting your project. |