Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # Problem Set 4
- # Name: Peyton Shields
- # Collaborators: None
- # Time Spent:
- # Late Days Used: (only if you are using any)
- import matplotlib.pyplot as plt
- import numpy as np
- from ps4_classes import BlackJackCard, CardDecks, Busted
- import copy
- #############
- # PROBLEM 1 #
- #############
- class BlackJackHand:
- """
- A class representing a game of Blackjack.
- """
- hit = 'hit'
- stand = 'stand'
- def __init__(self, deck):
- """
- Parameters:
- deck - An instance of CardDeck that represents the starting shuffled
- card deck (this deck itself contains one or more standard card decks)
- Attributes:
- self.deck - CardDeck, represents the shuffled card deck for this game of BlackJack
- self.player - list, initialized with the first 2 cards dealt to the player
- and updated as the player is dealt more cards from the deck
- self.dealer - list, initialized with the first 2 cards dealt to the dealer
- and updated as the dealer is dealt more cards from the deck
- Important: You MUST deal out the first four cards in the following order:
- player, dealer, player, dealer
- """
- # TODO
- self.deck = deck
- self.player = []
- self.dealer = []
- for i in range(2): #alternates between the player then dealer
- self.player.append(deck.deal_card())
- self.dealer.append(deck.deal_card())
- # You can call the method below like this:
- # BlackJackHand.best_val(cards)
- @staticmethod
- def best_val(cards):
- """
- Finds the best sum of point values given a list of cards, where the
- "best sum" is defined as the highest point total not exceeding 21.
- Remember that an Ace can have value 1 or 11.
- Hint: If you have one Ace, give it a value of 11 by default. If the sum
- point total exceeds 21, then give it a value of 1. What should you do
- if cards has more than one Ace?
- Parameters:
- cards - a list of BlackJackCard instances.
- Returns:
- int, best sum of point values of the cards
- """
- # TODO
- card_ranks = []
- card_vals = [] # ace value of 11
- for card in cards:
- rank = card.get_rank() # gets rank of each card
- card_ranks.append(rank) # adds the ranks to a list
- card_vals.append(card.get_val()) # adds value to a list
- point_value = sum(card_vals) # checks current value
- if point_value == 21: # standard win case
- return point_value
- elif "A" in card_ranks:
- while point_value > 21 and 11 in card_vals:
- card_vals.remove(11) # changes ace value from 11 to 1
- card_vals.append(1)
- point_value = sum(card_vals) # recalculates sum
- if point_value <= 21:
- return point_value
- return point_value
- def get_player_cards(self):
- """
- Returns:
- list, a copy of the player's cards
- """
- return copy.deepcopy(self.player)
- def get_dealer_cards(self):
- """
- Returns:
- list, a copy of the dealer's cards
- """
- # TODO
- return copy.deepcopy(self.dealer)
- def get_dealer_upcard(self):
- """
- Returns the dealer's face up card. We define the dealer's face up card
- as the first card in their hand.
- Returns:
- BlackJackCard instance, the dealer's face-up card
- """
- # TODO
- return self.dealer[0]
- def set_initial_cards(self, player_cards, dealer_cards):
- """
- Sets the initial cards of the game.
- player_cards - list, containing the inital player cards
- dealer_cards - list, containing the inital dealer cards
- used for testing, DO NOT MODIFY
- """
- self.player = player_cards[:]
- self.dealer = dealer_cards[:]
- # Strategy 1
- def mimic_dealer_strategy(self):
- """
- A playing strategy in which the player uses the same metric as the
- dealer to determine their next move.
- The player will:
- - hit if the best value of their cards is less than 17
- - stand otherwise
- Returns:
- str, "hit" or "stand" representing the player's decision
- """
- beginning_val = self.best_val(self.player)
- if beginning_val < 17: # standard implementation of dealer strategy
- return "hit"
- return "stand"
- # Strategy 2
- def peek_strategy(self):
- """
- A playing strategy in which the player knows the best value of the
- dealer's cards.
- The player will:
- - hit if the best value of their hand is less than that of the dealer's
- - stand otherwise
- Returns:
- str, "hit" or "stand" representing the player's decision
- """
- # TODO
- player_best_val = self.best_val(self.player)
- dealer_best_val = self.best_val(self.dealer)
- if player_best_val < dealer_best_val: # standard implementation of peek strategy
- return "hit"
- return "stand"
- # Strategy 3
- def simple_strategy(self):
- """
- A playing strategy in which the player will
- - stand if one of the following is true:
- - the best value of player's hand is greater than or equal to 17
- - the best value of player's hand is between 12 and 16 (inclusive)
- AND the dealer's up card is between 2 and 6 (inclusive)
- - hit otherwise
- Returns:
- str, "hit" or "stand" representing the player's decision
- """
- # TODO
- player_best_val = self.best_val(self.player)
- dealer_best_val = self.best_val(self.dealer)
- # next line just joins conditions together as specified in simple strategy guidelines
- if (player_best_val >= 17) or ((12 <= player_best_val <= 16) and (2 <= dealer_best_val <= 6)):
- return "stand"
- return "hit"
- def dealer_strategy(self):
- '''
- Basically the exact same as mimic dealer strategy, however it is the dealer who is employing the strategy
- in this case.
- :return: str, "hit" or "stand" representing the dealer's decision
- '''
- beginning_val = self.best_val(self.dealer)
- if beginning_val < 17: # standard implementation of dealer strategy
- return "hit"
- return "stand"
- def play_player(self, strategy):
- """
- Plays a full round of the player's turn and updates the player's hand
- to include new cards that have been dealt to the player. The player
- will be dealt a new card until they stand or bust.
- Parameter:
- strategy - function, one of the the 3 playing strategies defined in BlackJackHand
- (e.g. BlackJackHand.mimic_dealer_strategy)
- This function does not return anything. Instead, it:
- - Adds a new card to self.player each time the player hits.
- - Raises Busted exception (imported from ps4_classes.py) if the
- best value of the player's hand is greater than 21.
- """
- # TODO
- while strategy(self) == "hit":
- self.player.append(self.deck.deal_card()) # keeps adding cards to hand
- if self.best_val(self.player) > 21:
- raise Busted
- def play_dealer(self):
- """
- Plays a full round of the dealer's turn and updates the dealer's hand
- to include new cards that have been dealt to the dealer. The dealer
- will get a new card as long as the best value of their hand is less
- than 17, or they bust.
- This function does not return anything. Instead, it:
- - Adds a new card to self.dealer each time the dealer hits.
- - Raises Busted exception (imported from ps4_classes.py) if the
- best value of the dealer's hand is greater than 21.
- """
- # TODO
- while self.dealer_strategy() == "hit": # piggybacks off of mimic dealer function
- self.dealer.append(self.deck.deal_card()) # adds new card to deck
- if self.best_val(self.dealer) > 21:
- raise Busted
- def __str__(self):
- """
- Returns:
- str, representation of the player and dealer and dealer hands.
- Useful for debugging. DO NOT MODIFY.
- """
- result = 'Player: '
- for c in self.player:
- result += str(c) + ','
- result = result[:-1] + ' '
- result += '\n Dealer '
- for c in self.dealer:
- result += str(c) + ','
- return result[:-1]
- #############
- # PROBLEM 2 #
- #############
- def play_hand(deck, strategy, bet=1.0):
- """
- Plays a hand of Blackjack and determines the amount of money the player
- gets back based on their inital bet.
- The player will get:
- - 2.5 times their original bet if the player's first two cards equal 21,
- and the dealer's first two cards do not equal 21.
- - 2 times their original bet if the player wins after getting more
- cards or the dealer busts.
- - the original amount they bet if the game ends in a tie. If the
- player and dealer both get blackjack from their first two cards, this
- is also a tie.
- - 0 if the dealer wins or the player busts.
- Parameters:
- deck - an instance of CardDeck
- strategy - function, one of the the 3 playing strategies defined in BlackJackHand
- (e.g. BlackJackHand.mimic_dealer_strategy)
- bet - float, the amount that the player bets (default=1.0)
- Returns:
- float, the amount the player gets back
- """
- hand = BlackJackHand(deck)
- # player has 21 to start
- if hand.best_val(hand.get_player_cards()) == 21 and hand.best_val(hand.get_dealer_cards()) != 21:
- return 2.5 * bet
- try:
- hand.play_player(strategy) # player busts
- except Busted:
- return 0.0
- try:
- hand.play_dealer() # dealer busts
- except Busted:
- return 2.0 * bet
- if hand.best_val(hand.get_player_cards()) > hand.best_val(hand.get_dealer_cards()): # player wins
- return 2.0 * bet
- elif hand.best_val(hand.get_player_cards()) < hand.best_val(hand.get_dealer_cards()): # dealer wins
- return 0.0
- else:
- return float(bet) # results in a tie
- #############
- # PROBLEM 3 #
- #############
- def run_simulation(strategy, bet=2.0, num_decks=8, num_hands=20, num_trials=100, show_plot=False):
- """
- Runs a simulation and generates a box plot reflecting the distribution of
- player's rates of return across all trials.
- The box plot displays the distribution of data based on the five number
- summary: minimum, first quartile, median, third quartile, and maximum.
- We also want to show the average on the box plot. You can do this by
- specifying another parameter: plt.boxplot(results, showmeans=True)
- For each trial:
- - instantiate a new CardDeck with the num_decks and type BlackJackCard
- - for each hand in the trial, call play_hand and keep track of how
- much money the player receives across all the hands in the trial
- - calculate the player's rate of return, which is
- 100*(total money received-total money bet)/(total money bet)
- Parameters:
- strategy - function, one of the the 3 playing strategies defined in BlackJackHand
- (e.g. BlackJackHand.mimic_dealer_strategy)
- bet - float, the amount that the player bets each hand. (default=2)
- num_decks - int, the number of standard card decks in the CardDeck. (default=8)
- num_hands - int, the number of hands the player plays in each trial. (default=20)
- num_trials - int, the total number of trials in the simulation. (default=100)
- show_plot - bool, True if the plot should be displayed, False otherwise. (default=False)
- Returns:
- tuple, containing the following 3 elements:
- - list of the player's rate of return for each trial
- - float, the average rate of return across all the trials
- - float, the standard deviation of rates of return across all trials
- """
- rates_of_return = []
- for trial in range(num_trials):
- deck = CardDecks(num_decks, BlackJackCard)
- total_money_received = 0
- total_money_bet = 0
- for hand in range(num_hands):
- total_money_received += play_hand(deck, strategy, bet)
- total_money_bet += bet
- rates_of_return.append(100 * (total_money_received - total_money_bet)/total_money_bet)
- avg_rate_of_return = np.mean(rates_of_return)
- std_dev = np.std(rates_of_return)
- plt.boxplot(rates_of_return, showmeans=True)
- plt.ylabel("% Return")
- plt.ylim(-80,80)
- plt.title("Player ROI on Playing " + str(num_hands) + " Hands (" + strategy.__name__ + ") \n" + \
- "(Mean = " + str(avg_rate_of_return)[0:5] + "%, SD = " + str(std_dev)[0:5] + "%)")
- if show_plot:
- plt.show()
- return (rates_of_return, avg_rate_of_return, std_dev)
- def run_all_simulations(strategies):
- """
- Runs the simulation for each strategy in strategies and generates a single
- graph with one box plot for each strategy. Each box plot should reflect the
- distribution of rates of return for each strategy.
- Make sure to label each plot with the name of the strategy.
- Parameters:
- strategies - list of strategies to simulate
- """
- for strategy in strategies:
- run_simulation(strategy)
- if __name__ == '__main__':
- # uncomment to test each strategy separately
- #run_simulation(BlackJackHand.mimic_dealer_strategy, show_plot=True)
- #run_simulation(BlackJackHand.peek_strategy, show_plot=True)
- #run_simulation(BlackJackHand.simple_strategy, show_plot=True)
- # uncomment to run all simulations
- # run_all_simulations([BlackJackHand.mimic_dealer_strategy,
- # BlackJackHand.peek_strategy, BlackJackHand.simple_strategy])
- pass
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement