Appendix - Code of Card Game

# Card class (full code)

```class Card:
suits = ["Clubs", "Diamonds", "Hearts", "Spades"]
ranks = ["narf", "Ace", "2", "3", "4", "5", "6", "7",
"8", "9", "10", "Jack", "Queen", "King"]

def __init__(self, suit=0, rank=0):
self.suit = suit
self.rank = rank

def __str__(self):
return (self.ranks[self.rank] + " of " + self.suits[self.suit])

def cmp(self, other):
# Check the suits
if self.suit > other.suit: return 1
if self.suit < other.suit: return -1
# Suits are the same... check ranks
if self.rank > other.rank: return 1
if self.rank < other.rank: return -1
# Ranks are the same... it's a tie
return 0

def __eq__(self, other):
# equality
return self.cmp(other) == 0

def __le__(self, other):
# less than or equal
return self.cmp(other) <= 0

def __ge__(self, other):
# greater than or equal
return self.cmp(other) >= 0

def __gt__(self, other):
# strictly greater than
return self.cmp(other) > 0

def __lt__(self, other):
# strictly less than
return self.cmp(other) < 0

def __ne__(self, other):
# not equal
return self.cmp(other) != 0
```

# Deck class (full code)

```class Deck:

def __init__(self):
self.cards = []
for suit in range(4):
for rank in range(1, 14):
self.cards.append(Card(suit, rank))

def print_deck(self):
for card in self.cards:
print(card)

def __str__(self):
s,spaces = "",""
for c in self.cards:
s = s + spaces + str(c) + "\n"
spaces += " "
return s

def shuffle(self):
import random
rng = random.Random()        # Create a random generator
num_cards = len(self.cards)
for i in range(num_cards):
j = rng.randrange(i, num_cards)
(self.cards[i], self.cards[j]) = (self.cards[j], self.cards[i])

def shuffle2(self):
import random
rng = random.Random()        # Create a random generator
rng.shuffle(self.cards)      # Use its shuffle method

def remove(self, card):
if card in self.cards:
self.cards.remove(card)
return True
else:
return False

def pop(self):
return self.cards.pop()

def is_empty(self):
return self.cards == []

def deal(self, hands, num_cards=None):
if num_cards==None :             # if no default value for how many cards
num_cards = len(self.cards)  # to deal then deal all cards in deck
num_hands = len(hands)
for i in range(num_cards):
if self.is_empty():
break                    # Break if out of cards
card = self.pop()            # Take the top card
hand = hands[i % num_hands]  # Whose turn is next?
```

# CardGame class (full code)

```class CardGame:
def __init__(self):
self.deck = Deck()
self.deck.shuffle()
```

# Hand class (full code)

```class Hand(Deck):

def __init__(self, name=""):
self.cards = []
self.name = name

def __str__(self):
s = "Hand " + self.name
if self.is_empty():
s += " is empty\n"
return s
else:
s += " contains\n"
return s + super().__str__()    # super call by making use of the super() function (preferred)

self.cards.append(card)
return self
```

# OldMaidHand class (full code)

```class OldMaidHand(Hand):

def remove_matches(self):
count = 0                               # counts number of matches that have been removed
original_cards = self.cards.copy()      # makes a copy of the original set of cards in your hand
for card in original_cards:             # iterate over all cards in your hand
match = Card(3 - card.suit, card.rank)
if match in self.cards:             # if the matching card is in your hand
self.cards.remove(card)         # remove the card from your hand
self.cards.remove(match)        # remove the match from your hand
count += 1                      # add one to the count of matches that have been removed
print("Hand {0}: {1} matches {2}".format(self.name, card, match))
return count                            # return number of matches that have been removed
```

# OldMaidGame class (full code)

```class OldMaidGame(CardGame):

def play(self, names):
# Remove Queen of Clubs
queen_clubs = Card(0,12)
self.deck.remove(queen_clubs)

# Make a hand for each player
self.hands = []
for name in names:
self.hands.append(OldMaidHand(name))

# Deal the cards
self.deck.deal(self.hands)
print("---------- Cards have been dealt")
self.print_hands()

# Remove initial matches
matches = self.remove_all_matches()
self.print_hands()

# Play until all 50 cards are matched
# in other words, until 25 pairs have been matched
print("---------- Play begins")
turn = 0
num_players = len(names)
while matches < 25:
matches += self.play_one_turn(turn)
turn = (turn + 1) % num_players

print("---------- Game is Over")
self.print_hands()

def print_hands(self):
for hand in self.hands:
print(hand)

def remove_all_matches(self):
count = 0
for hand in self.hands:
count += hand.remove_matches()
return count

def play_one_turn(self, i):
print("Player" + str(i) + ":")
if self.hands[i].is_empty():
return 0
neighbor = self.find_neighbor(i)
picked_card = self.hands[neighbor].pop()
print("Hand", self.hands[i].name, "picked", picked_card)
count = self.hands[i].remove_matches()
self.hands[i].shuffle()
return count

def find_neighbor(self, i):
num_hands = len(self.hands)
for next in range(1,num_hands):
neighbor = (i + next) % num_hands
if not self.hands[neighbor].is_empty():
return neighbor
```

# Sample output of a run of the game

```>>> OldMaidGame().play(["kim","charles","siegfried"])
```
```---------- Cards have been dealt
Hand kim contains
5 of Diamonds
10 of Diamonds
Ace of Clubs
Jack of Hearts
4 of Clubs
3 of Clubs
King of Diamonds
4 of Diamonds
10 of Clubs
Ace of Hearts
5 of Hearts
Queen of Diamonds
Jack of Diamonds
5 of Clubs
9 of Clubs

Hand charles contains
6 of Clubs
2 of Clubs
9 of Hearts
8 of Hearts
10 of Hearts
9 of Diamonds
7 of Hearts
3 of Diamonds
Jack of Clubs
3 of Hearts

Hand siegfried contains
7 of Clubs
6 of Diamonds
King of Hearts
2 of Diamonds
7 of Diamonds
2 of Hearts
4 of Hearts
King of Clubs
8 of Clubs
8 of Diamonds
Queen of Hearts
6 of Hearts
Ace of Diamonds

Hand kim: 5 of Diamonds matches 5 of Hearts
Hand kim: Ace of Clubs matches Ace of Spades
Hand kim: Jack of Hearts matches Jack of Diamonds
Hand charles: 6 of Clubs matches 6 of Spades
Hand charles: 9 of Hearts matches 9 of Diamonds
Hand charles: 3 of Diamonds matches 3 of Hearts
Hand siegfried: 6 of Diamonds matches 6 of Hearts
Hand siegfried: 2 of Diamonds matches 2 of Hearts
Hand siegfried: King of Clubs matches King of Spades
Hand kim contains
10 of Diamonds
4 of Clubs
3 of Clubs
King of Diamonds
4 of Diamonds
10 of Clubs
Ace of Hearts
Queen of Diamonds
5 of Clubs
9 of Clubs

Hand charles contains
2 of Clubs
8 of Hearts
10 of Hearts
7 of Hearts
Jack of Clubs

Hand siegfried contains
7 of Clubs
King of Hearts
7 of Diamonds
4 of Hearts
8 of Clubs
8 of Diamonds
Queen of Hearts
Ace of Diamonds

---------- Play begins
Player0:
Hand kim picked 7 of Spades
Player1:
Hand charles picked Ace of Diamonds
Player2:
Hand siegfried picked 7 of Spades
Hand siegfried: 7 of Clubs matches 7 of Spades
Player0:
Hand kim picked 9 of Spades
Hand kim: 9 of Clubs matches 9 of Spades
Player1:
Hand charles picked 8 of Clubs
Hand charles: 8 of Spades matches 8 of Clubs
Player2:
Hand siegfried picked Jack of Spades
Player0:
Hand kim picked Jack of Clubs
Player1:
Hand charles picked 3 of Spades
Player2:
Hand siegfried picked Ace of Hearts
Player0:
Hand kim picked 10 of Hearts
Hand kim: 10 of Diamonds matches 10 of Hearts
Player1:
Hand charles picked Queen of Hearts
Player2:
Hand siegfried picked 4 of Diamonds
Hand siegfried: 4 of Hearts matches 4 of Diamonds
Player0:
Hand kim picked 3 of Spades
Hand kim: 3 of Clubs matches 3 of Spades
Player1:
Hand charles picked King of Hearts
Player2:
Hand siegfried picked 4 of Clubs
Hand siegfried: 4 of Spades matches 4 of Clubs
Player0:
Hand kim picked King of Hearts
Hand kim: King of Diamonds matches King of Hearts
Player1:
Hand charles picked Jack of Spades
Player2:
Hand siegfried picked 5 of Clubs
Player0:
Hand kim picked 7 of Hearts
Player1:
Hand charles picked Ace of Hearts
Hand charles: Ace of Diamonds matches Ace of Hearts
Player2:
Hand siegfried picked Queen of Diamonds
Player0:
Hand kim picked 8 of Hearts
Player1:
Hand charles picked 5 of Clubs
Hand charles: 5 of Spades matches 5 of Clubs
Player2:
Hand siegfried picked Jack of Clubs
Player0:
Hand kim picked Queen of Spades
Player1:
Hand charles picked 2 of Spades
Hand charles: 2 of Clubs matches 2 of Spades
Player2:
Hand siegfried picked Queen of Spades
Player0:
Hand kim picked Queen of Hearts
Player1:
Hand charles picked Queen of Spades
Player2:
Hand siegfried picked 8 of Hearts
Hand siegfried: 8 of Diamonds matches 8 of Hearts
Player0:
Hand kim picked Queen of Spades
Player1:
Hand charles picked Jack of Clubs
Hand charles: Jack of Spades matches Jack of Clubs
Player2:
Hand siegfried picked Queen of Hearts
Hand siegfried: Queen of Diamonds matches Queen of Hearts
Player0:
Hand kim picked 10 of Spades
Hand kim: 10 of Clubs matches 10 of Spades
Player1:
Player2:
Hand siegfried picked Queen of Spades
Player0:
Hand kim picked 7 of Diamonds
Hand kim: 7 of Hearts matches 7 of Diamonds
---------- Game is Over
Hand kim is empty

Hand charles is empty

Hand siegfried contains