This is code for a text-based game of Blackjack.
I would also like advice on how can I implement a betting system in this program. For example starting with an amount of chips and choosing how much of them to bet.
import random
card_suit = ['Hearts', 'Diamonds', 'Clubs', 'Spades']
card_value = ['Ace', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King']
deck = [(value, suit) for suit in card_suit for value in card_value]
def card_points(card):
if card[0] in ['Jack', 'Queen', 'King']:
return 10
elif card[0] == 'Ace':
return 11
else:
return int(card[0])
random.shuffle(deck)
player_cards = [deck.pop(), deck.pop()]
dealer_cards = [deck.pop()]
player_points = sum(card_points(card) for card in player_cards)
dealer_points = sum(card_points(card) for card in dealer_cards)
def points(dealer_points, player_points, dealer_cards, player_cards):
while dealer_points < 17:
new_card = deck.pop()
dealer_cards.append(new_card)
dealer_points += card_points(new_card)
print("Dealer's Cards:", dealer_cards)
print("Dealer's Points:", dealer_points)
print("\n")
while True:
print("Dealer's Cards:", dealer_cards)
print("Dealer's Points:", dealer_points)
print("\n")
print("Player's Cards:", player_cards)
print("Player's Points:", player_points)
print("\n")
decision = input('What will you do? ["hit" for a new card, "stand" to end the game]: ').lower()
if decision == "hit":
new_card = deck.pop()
player_cards.append(new_card)
player_points = sum(card_points(card) for card in player_cards)
if player_points > 21:
print("Dealer's Cards:", dealer_cards)
print("Dealer's Points:", dealer_points)
print("Player's Cards:", player_cards)
print("Player's Points:", player_points)
print("Dealer wins (player has more than 21 points)")
break
elif decision == "stand":
while dealer_points < 17:
new_card = deck.pop()
dealer_cards.append(new_card)
dealer_points += card_points(new_card)
print("Dealer's Cards:", dealer_cards)
print("Dealer's Points:", dealer_points)
print("Player's Cards:", player_cards)
print("Player's Points:", player_points)
if player_points > 21:
print("Dealer wins (player has more than 21 points).")
elif dealer_points > 21:
print("You win! (dealer has more than 21 points)")
elif player_points > dealer_points:
print("You win! (you have more points than the dealer)")
elif player_points < dealer_points:
print("Dealer wins (dealer has more points than the player).")
else:
print("It's a tie.")
break
else:
print("Unknown input.")
continue
2 Answers 2
cryptic index
deck = [(value, suit) for ... ]
def card_points(card):
if card[0] in ['Jack', 'Queen', 'King']:
return 10
elif card[0] == 'Ace':
The tuples in that first line are very nice and pythonic. But this would have been even nicer:
from collections import namedtuple
Card = namedtuple('Card', 'value suit')
deck = [Card(value, suit) for ... ]
Then later on we could speak of card.value
without a cryptic [0]
subscript.
enum
Consider defining class Value(Enum):
,
and moving the card_points()
logic into that class.
It is reasonable that a Jack object could display one way
as a string yet also return 10
as a value.
unicode cards
The way you display cards is perfectly fine. It is worth noting that 52 unicode codepoints offer an alternate means of displaying them.
common logic
player_cards = [deck.pop(), deck.pop()]
dealer_cards = [deck.pop()]
player_points = sum(card_points(card) for card in player_cards)
dealer_points = sum(card_points(card) for card in dealer_cards)
Consider defining class Hand:
, and maintaining a list of Hands.
Then indexing it gives you either the player or the dealer,
and its .points()
method gives you its total value.
DRY
Several times you print four items: {player,dealer} {cards,points}. Please extract a helper function.
cite your reference
The code should mention up top what game it implements. From the link in the Review Context I initially thought you meant standard blackjack, but this code implements a variant. I don't see any logic for Ace sometimes being worth 11 and sometimes 1.
Overview
You've done a good job:
- You leveraged code written by others with the
import
- Used meaningful names for many of the variables
Here are some adjustments for you to consider, mainly for coding style.
Layout
I recommend moving the functions to the top, after the import
.
Having them in the middle of the code interrupts the natural flow of the
code (from a human readability standpoint).
Unused code
I was about to recommend changing the name of the points
function because
it seemed too generic. However, I realized that it is not used, so it
can be deleted.
Documentation
The card_points
function always returns 11 for the Ace. The normal rules of
Blackjack allow for the Ace to have a value of 1 in some circumstances.
You should add documentation to describe whether or not the Ace can have a value of 1.
Input
It is great that you cast the user input into lower-case. It would also be helpful
to allow the user to be lazy and just input h
for "hit" or s
for "stand".
DRY
These lines appear 3 times in the code:
print("Dealer's Cards:", dealer_cards)
print("Dealer's Points:", dealer_points)
print("Player's Cards:", player_cards)
print("Player's Points:", player_points)
You could add them into a new function, named something like show_cards
,
then call the function 3 times.