In: Computer Science
Problem 1: Simulating Blackjack In this problem we will use classes and functions to simulate a simplified game of Blackjack (21). The game begins with a standard deck of 52 playing cards (no jokers). Each player is dealt two cards to start with. The winner of a hand of Blackjack is the player whose hand has the highest value without going over 21.
When calculating the value of a hand, we add up the rank of each card in the player's hand, where the numbered cards have ranks 2 through 10. The face cards, Jack, King, and Queen, each add 10 to the value of a player's hand. The Ace card can be treated as adding either 1 or 11 to the value of the player's hand, depending upon which brings the player closer to winning.
Player's may request additional cards (a "hit") in order to bring the value of their hand closer to 21. However, if the value of a player's hand rises above 21, then the player has "busted" and they automatically lose the game.
In our simulation we are ignoring the distinction between player and dealer. We are also ignoring betting, and so all the more sophisticated player actions (such as "splitting") are also being ignored. The behavior of player's is going to be fixed by a simple algorithm. Details for writing the simulation program are given below.
The program will consist of 4 classes: Card, Deck, Player, Blackjack. Each class represents objects that are elements of a simulated game of Blackjack. To implement each class you will have to complete the implementation of the functions inside the body of the class definition. The names of the classes, the functions, and the function parameters have already been given. DO NOT CHANGE THEM.
The Card class is meant to represent a single playing card. It has two attributes, suit and rank. Playing cards come in one of four suits: Hearts, Diamonds, Spades, and Clubs. In your program, each suit is represented by a string of a single capital letter: "H" for Hearts, "D" for Diamonds, "S" for Spades, and "C" for Clubs. I have included a list of the suits as a global variable in your program. For each suit there is a Card of one of 13 ranks. Each rank is represented by a string: "2" through "10" for the ranks of the numbered cards, and "J", "Q", "K", and "A" for the Jack, Queen, King, and Ace face Cards.
When a card is constructed the values for suit and rank should be passed to the suit and rank attributes of the Card class. You must implement this in the __init__() function. You should check that the values passed to the Card constructor represent correct suit and rank values.
The Deck class represents a standard deck of 52 playing cards. The Deck class should have a single attribute called cards. cards will be a list of Card objects, one for each playing card that makes up a standard deck. In the __init__() function of the Deck class you should create and add a Card object for each of the 52 cards that make up a standard playing card deck. That is, for each suit there should be a Card of each rank added to the cards list in the Deck class.
In addition to the __init__() method, you must also implement a deal_card() function. This function takes a single argument, an object of the Player class. Inside the function you should remove the card from the top of the Deck (from the cards list of the Deck), and then add that card to the hand attribute inside the Player object. I have provided you with a function shuffle_deck() that will randomize the order of the cards inside cards list inside the Deck object.
The function takes a single positive integer that represents how many times the deck will be shuffled. The default value is 5. DO NOT CHANGE THIS FUNCTION. The Player class represents the individual players involved in a game of Blackjack. Each player has three attributes: name, hand, and status. The name attribute is a string that represents the Player's name. The hand attribute is a list that will contain the Card objects that make up the Player's hand.
The status attribute will hold a Boolean value and represents whether the Player is still playing. When you construct a Player object, you should set the Player's name to the string passed in as an argument, the hand attribute should be set to an empty list, and the status attribute should be set to True. Once a Deck and Player have been instantiated, then you can deal cards to the Player from the Deck using the Deck's deal_card() function. If the Player decides to stay or busts during the game, then status will be set to False. In addition to __init__() function of the Player class, you must implement 2 other functions for Player objects.
The first function is called value(). It is used to calculate the current value of the Player's hand. Use the rank of each Card object in the Player's hand to calculate the sum, by adding the ranks together. Remember that the face cards, "J", "Q", and "K" each add 10 to the value of the Player's hand. Be very careful about Ace Cards. Remember that the Ace can add either 1 or 11 to the value of the Player's hand depending upon the circumstances.
The value() function should return the current total value of the Player's hand as an integer. The second function you must implement for the Player class is the choose_play() function. This function will determine whether the Player will hit—take another card—or stay—refuse cards if the Player is satisfied with the current total value of their hand. In our simulation all Players will follow this strategy.
If the current total value of their hand is less than 17, then the Player will hit. Otherwise, the Player will stay. If the Player decides to stay, then their status attribute should be set to False. The choose_play() function should return the string, "Hit", if the Player decides to hit, and return the string, "Stay", if the Player decides to stay.
The last class you must implement is the Blackjack class. This class represents a simulated game of Blackjack. Each Blackjack object has two attributes: players and deck. The players attribute is a list of Player objects. This list of Player objects is passed to the __init__() function of the Blackjack class when constructing a new Blackjack object. The deck attribute should be assigned a new Deck object. You must do two other things in the __init__() function of the Blackjack class. You must shuffle the deck. You must then deal two cards to each of the Players.
You can assume that the list of Players passed to the Blackjack constructor will always contain between 1 and 4 Player objects. In addition to the __init__() function of the Blackjack class, you must also implement a function called play_game(). This is the function where game play will happen.
Gameplay should occur inside of a loop. The loop continues until all of the Player's stop taking new cards. During each iteration of the loop you should do the following two things. First, for each Player, check the status attribute of the Player. If their status is True, then call the choose_play() function to determine what that Player will do. If choose_play() returns "Hit" for that Player, then deal that Player a new card from the Blackjack deck.
Then, check the value() of that Player's hand. If they have gone above 21, then report that Player has busted (print a message) and set the Player's status attribute to False. If choose_play() returns "Stay" for the Player, then move on to the next Player. Second, for each Player check their status attribute. If status attribute for all Players is set to False, then the game is done and you can end the game play loop. Once the loop is complete, then you need to determine the winner.
The winner is the Player whose hand has the highest value less than or equal to 21. If there is a winner, print a message reporting the winner of the game. If there is a tie, print a message reporting the tie.
If there is no winner (if all the Players busted), then print a message reporting that there is no winner. If you implement each of these classes and their functions correctly, then the test code included in the file will run a simulated game of Blackjack with four players.
Python Code So far
# DON'T CHANGE OR REMOVE THIS IMPORT
from random import shuffle
# DON'T CHANGE OR REMOVE THESE LISTS
# The first is a list of all possible card ranks: 2-10, Jack, King,
Queen, Ace
# The second is a list of all posible card suits: Hearts, Diamonds,
Clubs, Spades
ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q",
"K", "A"]
suits = ["H", "D", "C", "S"]
# This class represents an individual playing card
class Card():
def __init__(self, suit, rank):
pass # REMOVE THIS AND REPLACE WITH YOUR CODE
# DON'T CHANGE OR REMOVE THIS
# This function creates a string out of a Card for easy
printing.
def __str__(self):
return "[" + self.suit + ", " + self.rank + "]"
# This class represents a deck of playing cards
class Deck():
def __init__(self):
pass # REMOVE THIS AND REPLACE WITH YOUR CODE
# DON'T CHANGE OR REMOVE THIS
# This function will shuffle the deck, randomizing the order of the
cards
# inside the deck.
# It takes an integer argument, which determine how many times the
deck is
# shuffled.
def shuffle_deck(self, n = 5):
for i in range(n):
shuffle(self.cards)
# This function will deal a card from the deck. The card should
be removed
# from the deck and added to the player's hand.
def deal_card(self, player):
pass # REMOVE THIS AND REPLACE WITH YOUR CODE
# DON"T CHANGE OR REMOVE THIS
# This function constructs a string out of a Deck for easy
printing.
def __str__(self):
res = "[" + str(self.cards[0])
for i in range(1, len(self.cards)):
res += ", " + str(self.cards[i])
res += "]"
return res
# This class represents a player in a game of Blackjack
class Player():
def __init__(self, name):
pass # REMOVE THIS AND REPLACE WITH YOUR CODE
def value(self):
pass # REMOVE THIS AND REPLACE WITH YOUR CODE
def choose_play(self):
pass # REMOVE THIS AND REPLACE WITH YOUR CODE
# DON'T CHANGE OR REMOVE THIS
# This function creates a string representing a player for easy
printing.
def __str__(self):
res = "Player: " + self.name + "\n"
res += "\tHand: " + str(self.hand[0])
for i in range(1, len(self.hand)):
res += ", " + str(self.hand[i])
res += "\n"
res += "\tValue: " + str(self.value())
return res
# This class represents a game of Blackjack
class Blackjack():
def __init__(self, players):
pass # REMOVE THIS AND REPLACE WITH YOUR CODE
def play_game(self):
pass # REMOVE THIS AND REPLACE WITH YOUR CODE
# DON'T CHANGE OR REMOVE THIS
# This function creates a string representing the state of a
Blackjack game
# for easy printing.
def __str__(self):
res = "Current Deck:\n\t" + str(self.deck)
res = "\n"
for p in self.players:
res += str(p)
res += "\n"
return res
# DO NOT DELETE THE FOLLOWING LINES OF CODE! YOU MAY
# CHANGE THE FUNCTION CALLS TO TEST YOUR WORK WITH
# DIFFERENT INPUT VALUES.
if __name__ == "__main__":
# Uncomment each section of test code as you finish implementing
each class
# for this problem. Uncomment means remove the '#' at the front of
the line
# of code.
# Test Code for your Card class
#c1 = Card("H", "10")
#c2 = Card("C", "A")
#c3 = Card("D", "7")
#print(c1)
#print(c2)
#print(c3)
print()
# Test Code for your Deck class
#d1 = Deck()
#d1.shuffle_deck(10)
#print(d1)
print()
# Test Code for your Player class
#p1 = Player("Alice")
#p2 = Player("Bob")
#d1.deal_card(p1)
#d1.deal_card(p2)
#print(p1.value())
#print(p2.value())
#d1.deal_card(p1)
#d1.deal_card(p2)
#print(p1.value())
#print(p2.value())
#d1.deal_card(p1)
#d1.deal_card(p2)
#print(p1.value())
#print(p2.value())
#print(p1)
#print(p2)
#print(p1.choose_play())
#print(p2.choose_play())
print()
# Test Code for your Blackjack class
#players = [Player("Summer"), Player("Rick"), Player("Morty"),
Player("Jerry")]
#game = Blackjack(players)
#print(game)
#game.play_game()
#print(game)
Here is the completed working code:
# DON'T CHANGE OR REMOVE THIS IMPORT
from random import shuffle
# DON'T CHANGE OR REMOVE THESE LISTS
# The first is a list of all possible card ranks: 2-10, Jack, King,
Queen, Ace
# The second is a list of all posible card suits: Hearts, Diamonds,
Clubs, Spades
ranks = ["2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q",
"K", "A"]
suits = ["H", "D", "C", "S"]
# This class represents an individual playing
card
class Card():
suit = ""
rank = ""
def __init__(self, suit, rank):
if suit in suits:
self.suit =
suit
if rank in ranks:
self.rank =
rank
# DON'T CHANGE OR REMOVE THIS
# This function creates a string out of a Card for easy
printing.
def __str__(self):
return "[" + self.suit + ", " +
self.rank + "]"
# This class represents a deck of playing
cards
class Deck():
cards = []
def __init__(self):
for i in ["H","D","C","S"]:
for a in
range(0,13):
if a in range(0,9):
card = Card(i,str(a+2))
else:
if a==9:
card =
Card(i,"J")
if a==10:
card =
Card(i,"K")
if a==11:
card =
Card(i,"Q")
if a==12:
card =
Card(i,"A")
self.cards.append(card)
# DON'T CHANGE OR REMOVE THIS
# This function will shuffle the deck, randomizing the order of the
cards
# inside the deck.
# It takes an integer argument, which determine how many times the
deck is
# shuffled.
def shuffle_deck(self, n = 5):
for i in range(n):
shuffle(self.cards)
# This function will deal a card from the deck. The
card should be removed
# from the deck and added to the player's hand.
def deal_card(self, player):
player.hand.append(self.cards[0])
self.cards.pop(0)
# DON"T CHANGE OR REMOVE THIS
# This function constructs a string out of a Deck for easy
printing.
def __str__(self):
res = "[" +
str(self.cards[0])
for i in range(1,
len(self.cards)):
res += ", " +
str(self.cards[i])
res += "]"
return res
# This class represents a player in a game of
Blackjack
class Player():
name=""
hand=[]
status=True
def __init__(self, name):
self.name = name
self.hand = []
self.status =
True
def value(self):
val=0
if len(self.hand)>0:
for i in
self.hand:
if i.rank in
["2","3","4","5","6","7","8","9","10",]:
val+=int(i.rank)
elif i.rank in ["J","K","Q"]:
val+=10
else:
if val+11<=21:
val+=11
else:
val+=1
return val
def choose_play(self):
if self.value()<17:
return
"Hit"
else:
self.status=False
return
"Stay"
# DON'T CHANGE OR REMOVE THIS
# This function creates a string representing a player for easy
printing.
def __str__(self):
res = "Player: " + self.name +
"\n"
res += "\tHand: " +
str(self.hand[0])
for i in range(1,
len(self.hand)):
res += ", " +
str(self.hand[i])
res +=
"\n"
res += "\tValue: " +
str(self.value())
return res
# This class represents a game of Blackjack
class Blackjack():
def __init__(self, players):
self.players = players
self.deck = Deck()
self.deck.shuffle_deck()
for player in self.players:
self.deck.deal_card(player)
self.deck.deal_card(player)
def play_game(self):
for player in self.players:
if
player.status:
play = player.choose_play()
while(play=="Hit"and player.status):
self.deck.deal_card(player)
if
player.value()>21:
print(player.name, "is Busted!")
player.status=False
else:
play =
player.choose_play()
if play=="Stay":
continue
winner=self.players[0]
tie=[]
for i in
range(1,len(self.players)):
if
winner.value()>21:
winner=self.players[i]
continue
if
self.players[i].value()>winner.value()and
self.players[i].value()<=21 and winner.value()<=21:
winner=self.players[i]
elif
self.players[i].value()==winner.value() and
self.players[i].value()<=21 and winner.value()<=21:
tie.append(self.players[i])
winner=self.players[i]
if len(tie)==0:
print("The
Winner is ",winner.name)
else:
if winner not in
tie:
print("The Winner is ",winner.name)
return
else:
print("There has been a tie
between\n",winner.name)
for player in tie:
print(player.name)
# DON'T CHANGE OR REMOVE THIS
# This function creates a string representing the state of a
Blackjack game
# for easy printing.
def __str__(self):
res = "Current Deck:\n\t" +
str(self.deck)
res = "\n"
for p in self.players:
res +=
str(p)
res +=
"\n"
return res
# DO NOT DELETE THE FOLLOWING LINES OF CODE! YOU
MAY
# CHANGE THE FUNCTION CALLS TO TEST YOUR WORK WITH
# DIFFERENT INPUT VALUES.
if __name__ == "__main__":
# Uncomment each section of test code as you finish implementing
each class
# for this problem. Uncomment means remove the '#' at the front of
the line
# of code.
# Test Code for your Card class
c1 = Card("H", "10")
c2 = Card("C", "A")
c3 = Card("D", "7")
print(c1)
print(c2)
print(c3)
print()
# Test Code for your Deck class
d1 = Deck()
d1.shuffle_deck(10)
print(d1)
print()
# Test Code for your Player class
p1 = Player("Alice")
p2 = Player("Bob")
d1.deal_card(p1)
d1.deal_card(p2)
print(p1.value())
print(p2.value())
d1.deal_card(p1)
d1.deal_card(p2)
print(p1.value())
print(p2.value())
d1.deal_card(p1)
d1.deal_card(p2)
print(p1.value())
print(p2.value())
print(p1)
print(p2)
print(p1.choose_play())
print(p2.choose_play())
print()
# Test Code for your Blackjack
class
players = [Player("Summer"), Player("Rick"),
Player("Morty"), Player("Jerry")]
game = Blackjack(players)
print(game)
game.play_game()
print(game)
The program is quite long so if you cannot understand any part of it, please ask in the comment section, I will explain it.
If you find this useful, do uprate. Thanks.