Last active
August 29, 2015 13:57
-
-
Save calebreister/9621947 to your computer and use it in GitHub Desktop.
This is a console implementation of the game 21 (Blackjack). I did it in C++ for CS161, but now I have redone it in Python and made it more "Pythonic".
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
Game logic for 21 aka Blackjack | |
''' | |
import util | |
class WinReason: | |
PLAYER_BUST, DEALER_BUST, PLAYER_21, DEALER_21 = range(4) | |
# Much of Python is convention, the developer saw no need | |
# for extra features such as const declarations | |
DECK_SIZE = 52 | |
PLAYER_SIZE = 10 | |
DEALER_SIZE = 10 | |
''' | |
FUNCTION: cardValue | |
DESCRIPTION: Returns the input card's value (in the context of 21) | |
- Ace turns into 11 (and 1 if time) | |
- Face cards are 10 | |
- All other cards are their rank | |
PARAMETERS: | |
card (I) - the card to get the point value of | |
RETURN VALUES: the point value of the card | |
''' | |
def cardValue(card): | |
val = card % 100 | |
if val == 13 or val == 12 or val == 11: | |
return 10 | |
elif card % 100 == 1: | |
return 11 | |
else: | |
return card % 100 | |
''' | |
FUNCTION: drawCard | |
DESCRIPTION: returns the top card off the deck | |
The top card is the first card in the given array | |
that has a value greater than 0. After pulling the value, | |
replace it with a 0. | |
PARAMETERS: | |
deck (I/O) - the array from which to pull the card, | |
output because the value pulled is also replaced with a 0 | |
size (I) - the size of the deck | |
RETURN VALUES: | |
if deck is empty return 0 | |
''' | |
def drawCard(deck): | |
for i in range(len(deck)): | |
if deck[i] == 0: | |
#dynamically remove deck item | |
deck.remove(deck[i]) | |
top = deck[0] | |
deck.remove(deck[0]) | |
return top | |
''' | |
FUNCTION: handSum | |
DESCRIPTION: computes and returns the sum of the given hand | |
PARAMETERS: | |
hand (I) - the hand to sum | |
RETURN VALUES: the sum of the hand | |
''' | |
def handSum(hand): | |
cardSum = 0 | |
for i in range(len(hand)): | |
cardSum += cardValue(hand[i]) | |
return cardSum | |
''' | |
FUNCTION: CountCards | |
DESCRIPTION: count the number of items without a value of 0 in an array | |
PARAMETERS: | |
-I deck[]: the array to count | |
-I size: the size of the array | |
RETURN VALUES: the number of nonzero items in the array | |
''' | |
def countCards(deck): | |
count = 0 | |
for i in range(len(deck)): | |
if deck[i] != 0: | |
count += 1 | |
return count | |
''' | |
FUNCTION: AskPlayer | |
DESCRIPTION: prompts the user with a yes or no question | |
PARAMETERS: | |
-I question: the yes-no question to ask | |
RETURN VALUES: | |
true if user input is 'y' | |
false otherwise | |
''' | |
def askPlayer(question): | |
print("\n[Y/N]", question, end=' ') | |
ans = input() | |
if ans == 'y' or input == 'Y': | |
return True | |
else: return False | |
''' | |
FUNCTION: PlayHand | |
DESCRIPTION: the game logic implementation of 21 | |
PARAMETERS: | |
-I/O deck[]: the deck to use and manipulate | |
RETURN VALUES: enumerated | |
- PLAYER_BUST: if player gets total over 21 | |
- PLAYER_21: condition shown at end | |
- DEALER_BUST: if dealer gets total over 21 | |
- DEALER_21: condition shown at endy | |
''' | |
def playHand(deck): | |
player = [0, 0] | |
dealer = [0, 0] | |
for i in range(2): | |
#In Python, it appears that everything is dynamic | |
player.append(drawCard(deck)) | |
dealer.append(drawCard(deck)) | |
print(player) | |
print(dealer) | |
util.handPrint(dealer, "Dealer's Hand:", False, True) | |
util.handPrint(player, "Your Hand:") | |
while handSum(player) <= 21: | |
if askPlayer("Do you want another card?"): | |
player.append(drawCard(deck)) | |
util.handPrint(player, "", False) | |
#Dealer won | |
if handSum(player) > 21: | |
return WinReason.PLAYER_BUST | |
util.handPrint(dealer, "Dealer's Hand:") | |
while handSum(dealer) < 17: | |
dealer.append(drawCard(deck)) | |
util.handPrint(dealer, "Dealer's hand:") | |
#player wins | |
if handSum(dealer) > 21: | |
return WinReason.DEALER_BUST | |
if handSum(dealer) >= handSum(player): | |
return WinReason.DEALER_21#dealer wins | |
else: return WinReason.PLAYER_21#player wins |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3.3 | |
import random | |
from game import * | |
deck = util.deckInit() | |
random.shuffle(deck) | |
print(deck) | |
#Creating the Pythonic equivalent of a do...while loop | |
#create an infinte loop and then a fail condition | |
#fairly common, although poor practice | |
while True: | |
winner = playHand(deck) | |
print() | |
if winner == WinReason.PLAYER_BUST: | |
print("\nThe dealer won (you busted).") | |
elif winner == WinReason.PLAYER_21: | |
print("\nYou won (you got a 21)!") | |
elif winner == WinReason.DEALER_BUST: | |
print("\nYou won (the dealer busted)!") | |
elif winner == WinReason.DEALER_21: | |
print("\nThe dealer won (you don't have a 21).") | |
#exit condition | |
#not is not a function, it is an operator | |
if not(countCards(deck) > 15 and | |
askPlayer("Do you want to play again?")): | |
break |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
''' | |
Card iing key: | |
- rank will be A, 2, 3, 4, 5, 6, 7, 8, 9, 10, J, Q, or K | |
- suit will be displayed using the ASCII character | |
values 3 (heart), 4 (diamond), 5 (club), 6 (spade) | |
- takes a 3 digit number denoting the suit and card number | |
- 1st digit is the ASCII value of the suit | |
- Last 2 digits are the number of card | |
- 305 = 3 of hearts | |
- 512 = Jack of clubs | |
''' | |
''' | |
FUNCTION: DeckInit | |
DESCRIPTION: Initializes a "deck" of 52 cards to the correct numbers | |
and suits | |
RETURN: The generated deck | |
''' | |
def deckInit(): | |
i = 0 | |
card = 0 | |
deck = [] | |
while i < 13: | |
deck.append(card + 1 + 300) | |
card += 1 | |
i += 1 | |
card = 0 | |
while i < 26: | |
deck.append(card + 1 + 400) | |
card += 1 | |
i += 1 | |
card = 0 | |
while i < 39: | |
deck.append(card + 1 + 500) | |
card += 1 | |
i += 1 | |
card = 0 | |
while i < 52: | |
deck.append(card + 1 + 600) | |
card += 1 | |
i += 1 | |
card = 0 | |
return deck | |
# The deck can be printed directly, Python does not need to loop through and print | |
''' | |
Gets the suit of a card and outputs the unicode | |
value of the suit. | |
''' | |
def getSuit(card): | |
suit = int(card / 100) | |
if suit == 3: # heart | |
return '\u2665' | |
elif suit == 4: # diamond | |
return '\u2666' | |
elif suit == 5: # club | |
return '\u2663' | |
elif suit == 6: # spade | |
return '\u2660' | |
''' | |
FUNCTION: CardPrint | |
DESCRIPTION: displays the given card's rank and suit | |
PARAMETERS: | |
-I card: the card value to print | |
RETURN VALUES: prints the card and suit character | |
''' | |
def cardPrint(card): | |
num = card % 100 | |
if num == 13: # king | |
print('K', getSuit(card), sep='', end=' ') | |
elif num == 12: # queen | |
print('Q', getSuit(card), sep='', end=' ') | |
elif num == 11: # jack | |
print('J', getSuit(card), sep='', end=' ') | |
elif num == 1: # ace | |
print('A', getSuit(card), sep='', end=' ') | |
else: | |
print(num, getSuit(card), sep='', end=' ') | |
''' | |
FUNCTION: HandPrint | |
DESCRIPTION: prints an array of cards with the option to hide the first, | |
uses the same numbering system as CardPrint() | |
PARAMETERS: | |
-I cards[]: the cards to print | |
-I CardCount: number of cards to print | |
-I message: message to print in front of cards | |
-I OwnLine: creates new line for cards to print | |
-I HideTopCard: option to hide the top card (for the dealer in 21) | |
RETURN VALUES: prints cards | |
''' | |
def handPrint(cards, message, ownLine=True, hideTopCard=False): | |
i = 0 | |
if ownLine: | |
print() | |
print(message, end=' ') | |
if hideTopCard: | |
print('XX', end=' ') | |
i = 1 | |
for i in range(i, len(cards)): | |
#assert i < len(cards) | |
if cards[i] == 0: | |
continue | |
cardPrint(int(cards[i])) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment