Advertisement
Guest User

Untitled

a guest
Nov 15th, 2018
450
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 14.31 KB | None | 0 0
  1. # Problem Set 4
  2. # Name: Peyton Shields
  3. # Collaborators: None
  4. # Time Spent:
  5. # Late Days Used: (only if you are using any)
  6.  
  7. import matplotlib.pyplot as plt
  8. import numpy as np
  9. from ps4_classes import BlackJackCard, CardDecks, Busted
  10. import copy
  11.  
  12. #############
  13. # PROBLEM 1 #
  14. #############
  15. class BlackJackHand:
  16.     """
  17.    A class representing a game of Blackjack.  
  18.    """
  19.    
  20.     hit = 'hit'
  21.     stand = 'stand'
  22.  
  23.     def __init__(self, deck):
  24.         """
  25.        Parameters:
  26.        deck - An instance of CardDeck that represents the starting shuffled
  27.        card deck (this deck itself contains one or more standard card decks)
  28.  
  29.        Attributes:
  30.        self.deck - CardDeck, represents the shuffled card deck for this game of BlackJack
  31.        self.player - list, initialized with the first 2 cards dealt to the player
  32.                      and updated as the player is dealt more cards from the deck
  33.        self.dealer - list, initialized with the first 2 cards dealt to the dealer
  34.                      and updated as the dealer is dealt more cards from the deck
  35.                      
  36.        Important: You MUST deal out the first four cards in the following order:
  37.            player, dealer, player, dealer
  38.        """
  39.         # TODO
  40.         self.deck = deck
  41.         self.player = []
  42.         self.dealer = []
  43.  
  44.         for i in range(2): #alternates between the player then dealer
  45.             self.player.append(deck.deal_card())
  46.             self.dealer.append(deck.deal_card())
  47.  
  48.  
  49.     # You can call the method below like this:
  50.     #   BlackJackHand.best_val(cards)
  51.     @staticmethod
  52.     def best_val(cards):
  53.         """
  54.        Finds the best sum of point values given a list of cards, where the
  55.        "best sum" is defined as the highest point total not exceeding 21.
  56.  
  57.        Remember that an Ace can have value 1 or 11.
  58.        Hint: If you have one Ace, give it a value of 11 by default. If the sum
  59.        point total exceeds 21, then give it a value of 1. What should you do
  60.        if cards has more than one Ace?
  61.  
  62.        Parameters:
  63.        cards - a list of BlackJackCard instances.
  64.  
  65.        Returns:
  66.        int, best sum of point values of the cards  
  67.        """
  68.         # TODO
  69.         card_ranks = []
  70.         card_vals = [] # ace value of 11
  71.  
  72.         for card in cards:
  73.             rank = card.get_rank() # gets rank of each card
  74.             card_ranks.append(rank) # adds the ranks to a list
  75.             card_vals.append(card.get_val()) # adds value to a list
  76.  
  77.         point_value = sum(card_vals) # checks current value
  78.  
  79.         if point_value == 21: # standard win case
  80.             return point_value
  81.  
  82.         elif "A" in card_ranks:
  83.             while point_value > 21 and 11 in card_vals:
  84.                 card_vals.remove(11) # changes ace value from 11 to 1
  85.                 card_vals.append(1)
  86.                 point_value = sum(card_vals) # recalculates sum
  87.                 if point_value <= 21:
  88.                     return point_value
  89.  
  90.         return point_value
  91.  
  92.     def get_player_cards(self):
  93.         """
  94.        Returns:
  95.        list, a copy of the player's cards
  96.        """
  97.         return copy.deepcopy(self.player)
  98.  
  99.  
  100.     def get_dealer_cards(self):
  101.         """
  102.        Returns:
  103.        list, a copy of the dealer's cards
  104.        """
  105.         # TODO
  106.         return copy.deepcopy(self.dealer)
  107.  
  108.     def get_dealer_upcard(self):
  109.         """
  110.        Returns the dealer's face up card. We define the dealer's face up card
  111.        as the first card in their hand.
  112.  
  113.        Returns:
  114.        BlackJackCard instance, the dealer's face-up card
  115.        """
  116.         # TODO
  117.         return self.dealer[0]
  118.  
  119.     def set_initial_cards(self, player_cards, dealer_cards):
  120.         """
  121.        Sets the initial cards of the game.
  122.        player_cards - list, containing the inital player cards
  123.        dealer_cards - list, containing the inital dealer cards
  124.  
  125.        used for testing, DO NOT MODIFY
  126.        """
  127.         self.player = player_cards[:]
  128.         self.dealer = dealer_cards[:]
  129.  
  130.     # Strategy 1
  131.     def mimic_dealer_strategy(self):
  132.         """
  133.        A playing strategy in which the player uses the same metric as the
  134.        dealer to determine their next move.
  135.  
  136.        The player will:
  137.            - hit if the best value of their cards is less than 17
  138.            - stand otherwise
  139.  
  140.        Returns:
  141.        str, "hit" or "stand" representing the player's decision  
  142.        """
  143.         beginning_val = self.best_val(self.player)
  144.         if beginning_val < 17: # standard implementation of dealer strategy
  145.             return "hit"
  146.  
  147.         return "stand"
  148.  
  149.     # Strategy 2
  150.     def peek_strategy(self):
  151.         """
  152.        A playing strategy in which the player knows the best value of the
  153.        dealer's cards.
  154.  
  155.        The player will:
  156.            - hit if the best value of their hand is less than that of the dealer's
  157.            - stand otherwise
  158.  
  159.        Returns:
  160.        str, "hit" or "stand" representing the player's decision
  161.        """
  162.         # TODO
  163.         player_best_val = self.best_val(self.player)
  164.         dealer_best_val = self.best_val(self.dealer)
  165.  
  166.         if player_best_val < dealer_best_val: # standard implementation of peek strategy
  167.             return "hit"
  168.  
  169.         return "stand"
  170.  
  171.     # Strategy 3
  172.     def simple_strategy(self):
  173.         """
  174.        A playing strategy in which the player will
  175.            - stand if one of the following is true:
  176.                - the best value of player's hand is greater than or equal to 17
  177.                - the best value of player's hand is between 12 and 16 (inclusive)
  178.                  AND the dealer's up card is between 2 and 6 (inclusive)  
  179.            - hit otherwise
  180.  
  181.        Returns:
  182.        str, "hit" or "stand" representing the player's decision
  183.        """
  184.         # TODO
  185.         player_best_val = self.best_val(self.player)
  186.         dealer_best_val = self.best_val(self.dealer)
  187.  
  188.         # next line just joins conditions together as specified in simple strategy guidelines
  189.         if (player_best_val >= 17) or ((12 <= player_best_val <= 16) and (2 <= dealer_best_val <= 6)):
  190.             return "stand"
  191.  
  192.         return "hit"
  193.  
  194.     def dealer_strategy(self):
  195.         '''
  196.        Basically the exact same as mimic dealer strategy, however it is the dealer who is employing the strategy
  197.        in this case.
  198.        :return: str, "hit" or "stand" representing the dealer's decision
  199.        '''
  200.         beginning_val = self.best_val(self.dealer)
  201.         if beginning_val < 17:  # standard implementation of dealer strategy
  202.             return "hit"
  203.  
  204.         return "stand"
  205.  
  206.  
  207.     def play_player(self, strategy):
  208.         """
  209.        Plays a full round of the player's turn and updates the player's hand
  210.        to include new cards that have been dealt to the player. The player
  211.        will be dealt a new card until they stand or bust.
  212.  
  213.        Parameter:
  214.        strategy - function, one of the the 3 playing strategies defined in BlackJackHand
  215.                   (e.g. BlackJackHand.mimic_dealer_strategy)
  216.  
  217.        This function does not return anything. Instead, it:
  218.            - Adds a new card to self.player each time the player hits.
  219.            - Raises Busted exception (imported from ps4_classes.py) if the
  220.              best value of the player's hand is greater than 21.
  221.        """
  222.         # TODO
  223.         while strategy(self) == "hit":
  224.             self.player.append(self.deck.deal_card()) # keeps adding cards to hand
  225.  
  226.         if self.best_val(self.player) > 21:
  227.             raise Busted
  228.  
  229.  
  230.     def play_dealer(self):
  231.         """
  232.        Plays a full round of the dealer's turn and updates the dealer's hand
  233.        to include new cards that have been dealt to the dealer. The dealer
  234.        will get a new card as long as the best value of their hand is less
  235.        than 17, or they bust.
  236.  
  237.        This function does not return anything. Instead, it:
  238.            - Adds a new card to self.dealer each time the dealer hits.
  239.            - Raises Busted exception (imported from ps4_classes.py) if the
  240.              best value of the dealer's hand is greater than 21.
  241.        """
  242.         # TODO
  243.         while self.dealer_strategy() == "hit": # piggybacks off of mimic dealer function
  244.             self.dealer.append(self.deck.deal_card()) # adds new card to deck
  245.  
  246.         if self.best_val(self.dealer) > 21:
  247.             raise Busted
  248.  
  249.     def __str__(self):
  250.         """
  251.        Returns:
  252.        str, representation of the player and dealer and dealer hands.
  253.  
  254.        Useful for debugging. DO NOT MODIFY.
  255.        """
  256.         result = 'Player: '
  257.         for c in self.player:
  258.             result += str(c) + ','
  259.         result = result[:-1] + '    '
  260.         result += '\n   Dealer '
  261.         for c in self.dealer:
  262.             result += str(c) + ','
  263.         return result[:-1]
  264.  
  265. #############
  266. # PROBLEM 2 #
  267. #############
  268.  
  269.  
  270. def play_hand(deck, strategy, bet=1.0):
  271.     """
  272.    Plays a hand of Blackjack and determines the amount of money the player
  273.    gets back based on their inital bet.
  274.  
  275.    The player will get:
  276.  
  277.        - 2.5 times their original bet if the player's first two cards equal 21,
  278.          and the dealer's first two cards do not equal 21.
  279.        - 2 times their original bet if the player wins after getting more
  280.          cards or the dealer busts.
  281.        - the original amount they bet if the game ends in a tie. If the
  282.          player and dealer both get blackjack from their first two cards, this
  283.          is also a tie.
  284.        - 0 if the dealer wins or the player busts.
  285.  
  286.    Parameters:
  287.  
  288.        deck - an instance of CardDeck
  289.        strategy - function, one of the the 3 playing strategies defined in BlackJackHand
  290.                   (e.g. BlackJackHand.mimic_dealer_strategy)
  291.        bet - float, the amount that the player bets (default=1.0)
  292.  
  293.    Returns:
  294.  
  295.        float, the amount the player gets back
  296.    """
  297.     hand = BlackJackHand(deck)
  298.  
  299.     # player has 21 to start
  300.     if hand.best_val(hand.get_player_cards()) == 21 and hand.best_val(hand.get_dealer_cards()) != 21:
  301.         return 2.5 * bet
  302.  
  303.     try:
  304.         hand.play_player(strategy) # player busts
  305.     except Busted:
  306.         return 0.0
  307.  
  308.     try:
  309.         hand.play_dealer() # dealer busts
  310.     except Busted:
  311.         return 2.0 * bet
  312.  
  313.     if hand.best_val(hand.get_player_cards()) > hand.best_val(hand.get_dealer_cards()): # player wins
  314.         return 2.0 * bet
  315.     elif hand.best_val(hand.get_player_cards()) < hand.best_val(hand.get_dealer_cards()): # dealer wins
  316.         return 0.0
  317.     else:
  318.         return float(bet) # results in a tie
  319.  
  320.  
  321.  
  322. #############
  323. # PROBLEM 3 #
  324. #############
  325.  
  326.  
  327. def run_simulation(strategy, bet=2.0, num_decks=8, num_hands=20, num_trials=100, show_plot=False):
  328.     """
  329.    Runs a simulation and generates a box plot reflecting the distribution of
  330.    player's rates of return across all trials.
  331.  
  332.    The box plot displays the distribution of data based on the five number
  333.    summary: minimum, first quartile, median, third quartile, and maximum.
  334.    We also want to show the average on the box plot. You can do this by
  335.    specifying another parameter: plt.boxplot(results, showmeans=True)
  336.  
  337.    For each trial:
  338.  
  339.        - instantiate a new CardDeck with the num_decks and type BlackJackCard
  340.        - for each hand in the trial, call play_hand and keep track of how
  341.          much money the player receives across all the hands in the trial
  342.        - calculate the player's rate of return, which is
  343.            100*(total money received-total money bet)/(total money bet)
  344.  
  345.    Parameters:
  346.  
  347.        strategy - function, one of the the 3 playing strategies defined in BlackJackHand
  348.                   (e.g. BlackJackHand.mimic_dealer_strategy)
  349.        bet - float, the amount that the player bets each hand. (default=2)
  350.        num_decks - int, the number of standard card decks in the CardDeck. (default=8)
  351.        num_hands - int, the number of hands the player plays in each trial. (default=20)
  352.        num_trials - int, the total number of trials in the simulation. (default=100)
  353.        show_plot - bool, True if the plot should be displayed, False otherwise. (default=False)
  354.  
  355.    Returns:
  356.  
  357.        tuple, containing the following 3 elements:
  358.            - list of the player's rate of return for each trial
  359.            - float, the average rate of return across all the trials
  360.            - float, the standard deviation of rates of return across all trials
  361.    """
  362.     rates_of_return = []
  363.     for trial in range(num_trials):
  364.         deck = CardDecks(num_decks, BlackJackCard)
  365.         total_money_received = 0
  366.         total_money_bet = 0
  367.         for hand in range(num_hands):
  368.             total_money_received += play_hand(deck, strategy, bet)
  369.             total_money_bet += bet
  370.         rates_of_return.append(100 * (total_money_received - total_money_bet)/total_money_bet)
  371.  
  372.     avg_rate_of_return = np.mean(rates_of_return)
  373.     std_dev = np.std(rates_of_return)
  374.     plt.boxplot(rates_of_return, showmeans=True)
  375.     plt.ylabel("% Return")
  376.     plt.ylim(-80,80)
  377.     plt.title("Player ROI on Playing " + str(num_hands) + " Hands (" + strategy.__name__ + ") \n" + \
  378.         "(Mean = " + str(avg_rate_of_return)[0:5] + "%, SD = " + str(std_dev)[0:5] + "%)")
  379.     if show_plot:
  380.         plt.show()
  381.  
  382.     return (rates_of_return, avg_rate_of_return, std_dev)
  383.  
  384.  
  385. def run_all_simulations(strategies):
  386.     """
  387.    Runs the simulation for each strategy in strategies and generates a single
  388.    graph with one box plot for each strategy. Each box plot should reflect the
  389.    distribution of rates of return for each strategy.
  390.  
  391.    Make sure to label each plot with the name of the strategy.
  392.  
  393.    Parameters:
  394.  
  395.        strategies - list of strategies to simulate
  396.    """
  397.     for strategy in strategies:
  398.         run_simulation(strategy)
  399.  
  400.  
  401. if __name__ == '__main__':
  402.     # uncomment to test each strategy separately
  403.     #run_simulation(BlackJackHand.mimic_dealer_strategy, show_plot=True)
  404.     #run_simulation(BlackJackHand.peek_strategy, show_plot=True)
  405.     #run_simulation(BlackJackHand.simple_strategy, show_plot=True)
  406.  
  407.     # uncomment to run all simulations
  408. #    run_all_simulations([BlackJackHand.mimic_dealer_strategy,
  409. #                         BlackJackHand.peek_strategy, BlackJackHand.simple_strategy])
  410.     pass
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement