Skip to content

Instantly share code, notes, and snippets.

@finbarrtimbers
Last active August 29, 2015 14:03
Show Gist options
  • Save finbarrtimbers/4d4df708491cbe9d8669 to your computer and use it in GitHub Desktop.
Save finbarrtimbers/4d4df708491cbe9d8669 to your computer and use it in GitHub Desktop.
Text-based, one player blackjack game.
#!/usr/local/bin/python
"text-based Blackjack program. One player, one dealer; dealer hits to 17."
import random
import sys
class Card(object):
"Represents a playing card. Used here in DECK."
def __init__(self, name, value, suit, index):
self.name = name
self.value = value
self.suit = suit
self.index = index
def __unicode__(self):
temp = unicode(self.name + " of ") + suit_to_unicode(self.suit)
temp.encode('utf-8')
return temp
def __str__(self):
if UNICODE:
encoding = sys.stdout.encoding or DEFAULT_ENCODING
return unicode(self).encode(encoding, 'replace')
else:
return self.name + " of " + self.suit
def suit_to_unicode(suit):
"Converts a string representation of a suit to the unicode symbol."
if suit == "Spades":
return u"\u2660"
elif suit == "Hearts":
return u"\u2665"
elif suit == "Diamonds":
return u"\u2666"
elif suit == "Clubs":
return u"\u2663"
def card_suit(card_index):
"Converts the index of a card into the appropriate suit (as a string). "
if card_index >= 0 and card_index < 13:
suit = "Spades"
elif card_index >= 13 and card_index < 26:
suit = "Clubs"
elif card_index >= 26 and card_index < 39:
suit = "Diamonds"
elif card_index >= 39 and card_index < 52:
suit = "Hearts"
return suit
def card_name(card_index):
"Turns card index into a name. e.g. 13th card is a king."
if card_index == 0:
return 'Ace'
elif card_index > 0 and card_index < 10:
return str(card_index + 1)
elif card_index == 10:
return 'Jack'
elif card_index == 11:
return 'Queen'
elif card_index == 12:
return 'King'
else:
print card_index
raise ValueError
def card_value(card_index):
"Converts card_index into the card's value. e.g. King has a value of 10."
if card_index == 0:
return 11
elif card_index > 0 and card_index < 10:
return card_index + 1
elif card_index >= 10 and card_index <= 12:
return 10
else:
raise ValueError("n must be between 0 and 12")
def clear():
"Clears terminal"
import os
os.system('cls' if os.name == 'nt' else 'clear')
def deal_cards(n, cards_played=[]):
"deals n cards, while remembering which cards have been dealt."
hand = []
deck = {n : Card(card_name(n % 13), card_value(n % 13), card_suit(n), n)
for n in xrange(52)}
if len(cards_played) >= 52:
return deal_cards(n, [])
for i in xrange(n):
while True:
j = random.randrange(52)
if j not in cards_played:
cards_played.append(j)
break
hand.append(deck[j])
return hand
def get_hand_value(hand):
"Returns the total value of the hand."
ace_counter = 0
for card in hand:
if card.name == 'Ace':
ace_counter += 1
total = sum([card.value for card in hand])
if total > 21 and ace_counter > 0:
while total > 21 and ace_counter > 0:
total -= 10
ace_counter -= 1
return total
def print_hand(hand):
"Prints the hand to stdout."
print '-' * 15
for card in hand:
print card
print '-' * 15
print 'Total: ' + str(get_hand_value(hand)) + '\n'
def play_dealer(dealer_hand, silent=False):
"Plays for the dealer by hitting until 17."
hand_value = get_hand_value(dealer_hand)
if not silent:
print "Dealer's hand:"
print_hand(dealer_hand)
while hand_value < 17:
dealer_hand += deal_cards(1)
if not silent:
print "Dealer hits. Dealer's hand is now:"
print_hand(dealer_hand)
hand_value = get_hand_value(dealer_hand)
return dealer_hand
def end_hand(string):
"Ends the hand by printing the string and clearing the screen."
raw_input(string + "[Enter to continue]")
clear()
# TODO: add splitting.
# When a hand has a pair, then you can split into two hands.
# Requires doubling the bet.
# TODO: add double down.
# On the first turn, players can double their bet,
# take a single card, and stand.
# TODO: add surrendering.
# Player gives up a half-bet and retires from the game.
def play_hand(bet):
"Plays one hand of blackjack. Returns result of bet."
hand = deal_cards(2, [])
dealer = deal_cards(2)
i = 0
while True:
print "The dealer's hand:"
print_hand(dealer)
print "\nYour hand:"
print_hand(hand)
hand_value = get_hand_value(hand)
dealer_hand_value = get_hand_value(dealer)
if hand_value > 21:
end_hand("Sorry, you've gone bust.")
return -1* bet
if i == 0:
action_string = "[H]it [S]tand [D]ouble S[u]rrender [Q]uit:"
action = raw_input(action_string).lower()
else:
action = raw_input("[H]it [S]tand [Q]uit:").lower()
if action == "h":
hand += deal_cards(1)
elif action == "s":
dealer = play_dealer(dealer)
dealer_hand_value = get_hand_value(dealer)
if dealer_hand_value > 21 or dealer_hand_value < hand_value:
end_hand("You win!")
return bet
else:
end_hand("You lose!")
return 0
elif action == "p":
print "Not yet implemented, sorry!"
elif action == "d":
hand += deal_cards(1)
bet *= 2
dealer = play_dealer(dealer)
dealer_hand_value = get_hand_value(dealer)
if dealer_hand_value > 21 or dealer_hand_value < hand_value:
end_hand("You win!")
return bet
else:
end_hand("You lose!")
return 0
elif action == "u":
end_hand("Better luck next round.")
bet *= 0.5
return bet
else:
if action == 'q':
sys.exit(0)
else:
print "Invalid option."
i += 1
def main():
"Runs blackjack game."
try:
chips = 100.0
while chips != 0:
if chips == 0:
print "Sorry, you ran out of money. Have a nice day!"
choice = raw_input("Want to play a hand [y/n]? ")
if choice == 'y':
bet_message = "Bet [min: " + str(HOUSE_MIN)
bet_message += "; you have " + str(chips) + "]:"
bet_response = raw_input(bet_message)
try:
bet = float(bet_response)
assert bet >= HOUSE_MIN and bet <= chips
chips += play_hand(bet)
except (ValueError, AssertionError):
print "Invalid input."
elif choice == 'n':
raise SystemExit(0)
else:
print "Invalid choice."
# The try/except allows me to handle KeyboardInterrupts silently.
except (KeyboardInterrupt, EOFError):
pass
if __name__ == "__main__":
# set global variables
HOUSE_MIN = 1.0
UNICODE = True
DECK = {n : Card(card_name(n % 13), card_value(n % 13), card_suit(n), n)
for n in xrange(52)}
DEFAULT_ENCODING = 'utf-8'
#start playing
main()
from blackjack import *
import unittest
class TestBlackjack(unittest.TestCase):
def test_get_value(self):
self.assertTrue(len([get_hand_value(deal_cards(i, []))
for i in range(10)]) == 10)
def test_deal_cards(self):
self.assertTrue(len([play_dealer(deal_cards(2, []), silent=True)
for i in range(10)]) == 10)
def regression_tests(self):
hand1 = [Card(card_name(n % 13), card_value(n % 13), card_suit(n), n)
for n in [0, 5, 8, 12]]
hand2 = [Card(card_name(n % 13), card_value(n % 13), card_suit(n), n)
for n in [0, 13, 26, 39]]
self.assertTrue(get_hand_value(hand1) == 26)
self.assertTrue(get_hand_value(hand2) == 14)
if __name__ == "__main__":
suite = unittest.TestLoader().loadTestsFromTestCase(TestBlackjack)
unittest.TextTestRunner(verbosity=2).run(suite)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment