Blackjack game – how to avoid endlessly repeating code for each player?

Question:

I’m trying to write a blackjack game and finding that I’m repeating code a lot.

I know I should construct a for loop but my mind is like mush.

To set up:

import random

cards = [11, 2, 3, 4, 5, 6, 7, 8, 9, 10, 10, 10, 10]

def deal_card():
    return random.sample(cards, 2)
player_cards = deal_card()
computer_cards = deal_card()

Then I’m trying to calculate the score through some stages, including:

if 11 in player_cards and sum(player_cards) > 21:
    player_cards = player_cards.remove(11)
    player_cards = player_cards.append(1)
if 11 in computer_cards and sum(computer_cards) > 21:
    computer_cards = computer_cards.remove(11)
    computer_cards = computer_cards.append(1)

I don’t want to have to repeat all the code for both players but I’m struggling on the for loop.

Do I create a variable with the two lists (player_cards and computer_cards)?

Do I create a list of lists and loop through that?

Do I use map, zip or another Python tool?

Any ideas would be much appreciated.

Asked By: Foothill_trudger

||

Answers:

You can make a function to sum the cards and just call that on each hand, im not that familliar with the rules of blackjack but using your logic above i get this:

def sum_cards(hand):
    if 11 in hand and sum(hand) > 21:
        return sum(hand)-11
    else:
        return sum(hand)

with give this output:

>>> player_hand = [11,10]
>>> computer_hand =[11,11]
>>> sum_cards(player_hand)
21
>>> sum_cards(computer_hand)
11
Answered By: Bendik Knapstad

Probably the most straightforward way is to define a list of players (including the computer) and then use a dict to store cards. Here, I make separate lists of human and computer players, and then combine them to form the full list of players:

human_players = ["human 1"]
computer_players = ["computer 1"]
players = human_players + computer_players
hands = dict()
for p in players:
    hands[p] = deal_card()
...
for p in players:
    while 11 in hands[p] and sum(hands[p]) > 21:
        hands[p].remove(11)
        hands[p].append(1)
    if p in human_players:
        # do any human-only stuff here
    if p in computer_players :
        # do any computer-only stuff here
        

Some points to note:

  • This approach easily extends to games with more than 2 players.
  • Changed your "if" to a "while" because it’s possible to have more than one ace in hand. (Probably doesn’t matter – I think just about the only time this would make a difference is if you were dealt (10,A) and for some strange reason chose to draw another card, and got another ace. But it’s generally best to keep the code close to the underlying logic and not rely on "that case will never come up".)
  • Changed the syntax for your remove and append calls.

I assume player_cards = player_cards.remove(11) is intended to achieve the following:

  • retrieve the list named player_cards
  • create a new list, based on the old one but with 11 removed
  • overwrite the old player_cards with this new one.

But that’s not quite how it works. .remove() is a method that modifies the list and returns no value.

If you try player_cards=player_cards.remove(11), it will first remove the 11 as intended, but then it will overwrite player_cards with that no-value. Similarly for .append().

Note that in your current approach, cards dealt to one player are still available to be dealt to other players (and possibly to be dealt to the same player again!) I haven’t fixed this, but if that matters, you probably want to keep track of all undealt cards, deal by selection from the remaining undealt cards, and update that "undealt" info as you deal.

Answered By: Geoffrey Brent
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.