{ "cells": [ { "cell_type": "markdown", "metadata": { "collapsed": true }, "source": [ "# Milestone Project 2 - Solution\n", "Below is my implementation of a simple game of Blackjack. Notice the use of OOP and classes for the cards and hands." ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Let's start by defining some global objects for the cards, tuples and a dict." ] }, { "cell_type": "code", "execution_count": 2, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Used for card shuffle\n", "import random\n", "\n", "# Boolean used to know if hand is in play\n", "playing = False\n", "\n", "chip_pool = 100 # Could also make this a raw input.\n", "\n", "bet = 1\n", "\n", "restart_phrase = \"Press 'd' to deal the cards again, or press 'q' to quit\"" ] }, { "cell_type": "code", "execution_count": 3, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Hearts, Diamonds,Clubs,Spades\n", "suits = ('H','D','C','S')\n", "\n", "# Possible card ranks\n", "ranking = ('A', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K')\n", "\n", "# Point values dict (Note: Aces can also be 11, check self.ace for details)\n", "card_val = {'A':1, '2':2, '3':3, '4':4, '5':5, '6':6, '7':7, '8':8, '9':9, '10':10, 'J':10, 'Q':10, 'K':10}" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now I'll make a card class, it will have some basic ID functions, and then some functions to grab the suit and rank of the card." ] }, { "cell_type": "code", "execution_count": 4, "metadata": { "collapsed": true }, "outputs": [], "source": [ "# Create a card class\n", "class Card:\n", " \n", " def __init__(self,suit,rank):\n", " self.suit = suit\n", " self.rank = rank\n", " \n", " def __str__(self):\n", " return self.suit + self.rank\n", " \n", " def grab_suit(self):\n", " return self.suit\n", " \n", " def grab_rank(self):\n", " return self.rank\n", " \n", " def draw(self):\n", " print (self.suit + self.rank)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now I'll make a hand class, this class will have functions to take into account the Ace situation" ] }, { "cell_type": "code", "execution_count": 5, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# Create a hand class\n", "class Hand:\n", " \n", " def __init__(self):\n", " self.cards = []\n", " self.value = 0\n", " # Aces can be 1 or 11 so need to define it here\n", " self.ace = False\n", " \n", " def __str__(self):\n", " ''' Return a string of current hand composition'''\n", " hand_comp = \"\"\n", " \n", " # Better way to do this? List comprehension?\n", " for card in self.cards:\n", " card_name = card.__str__()\n", " hand_comp += \" \" + card_name\n", " \n", " return 'The hand has %s' %hand_comp\n", " \n", " def card_add(self,card):\n", " ''' Add another card to the hand'''\n", " self.cards.append(card)\n", " \n", " # Check for Aces\n", " if card.rank == 'A':\n", " self.ace = True\n", " self.value += card_val[card.rank]\n", " \n", " def calc_val(self):\n", " '''Calculate the value of the hand, make aces an 11 if they don't bust the hand'''\n", " if (self.ace == True and self.value < 12):\n", " return self.value + 10\n", " else:\n", " return self.value\n", " \n", " def draw(self,hidden):\n", " if hidden == True and playing == True:\n", " #Don't show first hidden card\n", " starting_card = 1\n", " else:\n", " starting_card = 0\n", " for x in range(starting_card,len(self.cards)):\n", " self.cards[x].draw()\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next I'll make a deck class" ] }, { "cell_type": "code", "execution_count": 6, "metadata": { "collapsed": true }, "outputs": [], "source": [ "class Deck:\n", " \n", " def __init__(self):\n", " ''' Create a deck in order '''\n", " self.deck = []\n", " for suit in suits:\n", " for rank in ranking:\n", " self.deck.append(Card(suit,rank))\n", " \n", " def shuffle(self):\n", " ''' Shuffle the deck, python actually already has a shuffle method in its random lib '''\n", " random.shuffle(self.deck)\n", " \n", " def deal(self):\n", " ''' Grab the first item in the deck '''\n", " single_card = self.deck.pop()\n", " return single_card\n", " \n", " def __str__(self):\n", " deck_comp = \"\"\n", " for card in self.cards:\n", " deck_comp += \" \" + deck_comp.__str__()\n", "\n", " return \"The deck has\" + deck_comp" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now that the classes are done, time for the cool part, creating the actual game!\n", "\n", "First off, making a bet. Need to check if the bet amount is within the integer." ] }, { "cell_type": "code", "execution_count": 7, "metadata": { "collapsed": false }, "outputs": [], "source": [ "# First Bet\n", "def make_bet():\n", " ''' Ask the player for the bet amount and '''\n", " \n", " global bet\n", " bet = 0\n", " \n", " print ' What amount of chips would you like to bet? (Enter whole integer please) '\n", " \n", " # While loop to keep asking for the bet\n", " while bet == 0:\n", " bet_comp = raw_input() # Use bet_comp as a checker\n", " bet_comp = int(bet_comp)\n", " # Check to make sure the bet is within the remaining amount of chips left.\n", " if bet_comp >= 1 and bet_comp <= chip_pool:\n", " bet = bet_comp\n", " else:\n", " print \"Invalid bet, you only have \" + str(chip_pool) + \" remaining\"\n", " \n", "\n", "\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Next, make a function setting up the game and for dealing out the cards." ] }, { "cell_type": "code", "execution_count": 8, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def deal_cards():\n", " ''' This function deals out cards and sets up round '''\n", " \n", " # Set up all global variables\n", " global result,playing,deck,player_hand,dealer_hand,chip_pool,bet\n", " \n", " # Create a deck\n", " deck = Deck()\n", " \n", " #Shuffle it\n", " deck.shuffle()\n", " \n", " #Set up bet\n", " make_bet()\n", " \n", " # Set up both player and dealer hands\n", " player_hand = Hand()\n", " dealer_hand = Hand()\n", " \n", " # Deal out initial cards\n", " player_hand.card_add(deck.deal())\n", " player_hand.card_add(deck.deal())\n", " \n", " dealer_hand.card_add(deck.deal())\n", " dealer_hand.card_add(deck.deal())\n", " \n", " result = \"Hit or Stand? Press either h or s: \"\n", " \n", " if playing == True:\n", " print 'Fold, Sorry'\n", " chip_pool -= bet\n", " \n", " # Set up to know currently playing hand\n", " playing = True \n", " game_step()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now make the hit function" ] }, { "cell_type": "code", "execution_count": 9, "metadata": { "collapsed": false }, "outputs": [], "source": [ "def hit():\n", " \n", " ''' Implement the hit button '''\n", " global playing,chip_pool,deck,player_hand,dealer_hand,result,bet\n", " \n", " # If hand is in play add card\n", " if playing:\n", " if player_hand.calc_val() <= 21:\n", " player_hand.card_add(deck.deal())\n", " \n", " print \"Player hand is %s\" %player_hand\n", " \n", " if player_hand.calc_val() > 21:\n", " result = 'Busted! '+ restart_phrase\n", " \n", " chip_pool -= bet\n", " playing = False\n", " \n", " else:\n", " result = \"Sorry, can't hit\" + restart_phrase\n", " \n", " game_step()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now make the stand function" ] }, { "cell_type": "code", "execution_count": 10, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def stand():\n", " global playing,chip_pool,deck,player_hand,dealer_hand,result,bet\n", " ''' This function will now play the dealers hand, since stand was chosen '''\n", " \n", " if playing == False:\n", " if player_hand.calc_val() > 0:\n", " result = \"Sorry, you can't stand!\"\n", " \n", " # Now go through all the other possible options\n", " else:\n", " \n", " # Soft 17 rule\n", " while dealer_hand.calc_val() < 17:\n", " dealer_hand.card_add(deck.deal())\n", " \n", " # Dealer Busts \n", " if dealer_hand.calc_val() > 21:\n", " result = 'Dealer busts! You win!' + restart_phrase\n", " chip_pool += bet\n", " playing = False\n", " \n", " #Player has better hand than dealer\n", " elif dealer_hand.calc_val() < player_hand.calc_val():\n", " result = 'You beat the dealer, you win!' + restart_phrase\n", " chip_pool += bet\n", " playing = False\n", " \n", " # Push\n", " elif dealer_hand.calc_val() == player_hand.calc_val():\n", " result = 'Tied up, push!' + restart_phrase\n", " playing = False\n", " \n", " # Dealer beats player\n", " else:\n", " result = 'Dealer Wins!' + restart_phrase\n", " chip_pool -= bet\n", " playing = False\n", " game_step()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Function to print results and ask user for next step" ] }, { "cell_type": "code", "execution_count": 11, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def game_step():\n", " 'Function to print game step/status on output'\n", " \n", " #Display Player Hand\n", " print \"\"\n", " print('Player Hand is: '),\n", " player_hand.draw(hidden =False)\n", " \n", " print 'Player hand total is: '+str(player_hand.calc_val())\n", " \n", " #Display Dealer Hand\n", " print('Dealer Hand is: '),\n", " dealer_hand.draw(hidden=True)\n", " \n", " # If game round is over\n", " if playing == False:\n", " print \" --- for a total of \" + str(dealer_hand.calc_val() )\n", " print \"Chip Total: \" + str(chip_pool)\n", " # Otherwise, don't know the second card yet\n", " else: \n", " print \" with another card hidden upside down\"\n", " \n", " # Print result of hit or stand.\n", " print result\n", " \n", " player_input()\n", " " ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Function for exiting the game" ] }, { "cell_type": "code", "execution_count": 12, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def game_exit():\n", " print 'Thanks for playing!'\n", " exit()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Function to read user input" ] }, { "cell_type": "code", "execution_count": 13, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def player_input():\n", " ''' Read user input, lower case it just to be safe'''\n", " plin = raw_input().lower()\n", " \n", " \n", " if plin == 'h':\n", " hit()\n", " elif plin == 's':\n", " stand()\n", " elif plin == 'd':\n", " deal_cards()\n", " elif plin == 'q':\n", " game_exit()\n", " else:\n", " print \"Invalid Input...Enter h, s, d, or q: \"\n", " player_input()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Make a quick intro for the game" ] }, { "cell_type": "code", "execution_count": 14, "metadata": { "collapsed": true }, "outputs": [], "source": [ "def intro():\n", " statement = '''Welcome to BlackJack! Get as close to 21 as you can without going over!\n", " Dealer hits until she reaches 17. Aces count as 1 or 11.\n", " Card output goes a letter followed by a number of face notation'''\n", " print statement" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now to play the game!" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [ "'''The following code will initiate the game! (Note: Need to Run all Cells)'''\n", "\n", "# Create a Deck\n", "deck = Deck()\n", "#Shuffle it\n", "deck.shuffle()\n", "# Create player and dealer hands\n", "player_hand = Hand()\n", "dealer_hand = Hand()\n", "#Print the intro\n", "intro()\n", "# Deal out the cards and start the game!\n", "deal_cards()" ] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": false }, "outputs": [], "source": [] }, { "cell_type": "code", "execution_count": null, "metadata": { "collapsed": true }, "outputs": [], "source": [] } ], "metadata": { "kernelspec": { "display_name": "Python 2", "language": "python", "name": "python2" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 2 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython2", "version": "2.7.11" } }, "nbformat": 4, "nbformat_minor": 0 }