Infinite looping Issue Python. Can't quit game
Question:
I made a code for Blackjack in Python and whenever I run blackjack_game(deck) saying no to the ‘Play Again’ input should quit the game but it doesn’t. Funds going zero and below should also trigger the game to quit but it doesn’t.
This is what it looks like:
import random
import os
# The Card class definition
class Card:
def __init__(self, suit, value, card_value):
# Suit of the Card like Spades and Clubs
self.suit = suit
# Representing Value of the Card like A for Ace, K for King
self.value = value
# Score Value for the Card like 10 for King
self.card_value = card_value
# Clear the terminal
def clear():
os.system("clear")
# Print player stats
def print_stats(player_name, funds, wins, losses, ties, blackjacks, busts):
print('Player: ', player_name)
print('Funds: $', funds)
print(f'Wins: {wins} Losses: {losses} Ties: {ties} Blackjacks: {blackjacks} Busts: {busts}')
# Function to print the cards
def print_cards(cards, hidden):
s = ""
for card in cards:
s = s + "t ________________"
if hidden:
s += "t ________________"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + "t| {} |".format(card.value)
else:
s = s + "t| {} |".format(card.value)
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| {} |".format(card.suit)
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + "t| {} |".format(card.value)
else:
s = s + "t| {} |".format(card.value)
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t|________________|"
if hidden:
s += "t|________________|"
print(s)
print()
# Function for a game of blackjack
def blackjack_game(deck):
end_game = False
play_again = 'Y'
# Player name
player_name = str(input('Enter player name: '))
# Intro
print('Lets have a fun game of Blackjack, ', player_name)
# Cards for both dealer and player
player_cards = []
dealer_cards = []
# Scores for both dealer and player
player_score = 0
dealer_score = 0
# Player stats
funds = 100
wins = 0
losses = 0
ties = 0
blackjacks = 0
busts = 0
bet = 0
clear()
# Current Stats Display
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
# Bets
while play_again == 'Y':
while end_game == False:
while funds > 0:
while bet == 0:
bet = int(input('Enter bet amount: '))
if bet > funds:
print('Insufficient funds')
bet = 0
# Initial dealing for player and dealer
while len(player_cards) < 2:
# Randomly dealing a card
player_card = random.choice(deck)
player_cards.append(player_card)
deck.remove(player_card)
# Updating the player score
player_score += player_card.card_value
# In case both the cards are Ace, make the first ace value as 1
if len(player_cards) == 2:
if player_cards[0].card_value == 11 and player_cards[1].card_value == 11:
player_cards[0].card_value = 1
player_score -= 10
# Print player cards and score
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
input()
# Randomly dealing a card
dealer_card = random.choice(deck)
dealer_cards.append(dealer_card)
deck.remove(dealer_card)
# Updating the dealer score
dealer_score += dealer_card.card_value
# Print dealer cards and score, keeping in mind to hide the second card and score
print("DEALER CARDS: ")
if len(dealer_cards) == 1:
print_cards(dealer_cards, False)
print("DEALER SCORE = ", dealer_score)
else:
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
# In case both the cards are Ace, make the second ace value as 1
if len(dealer_cards) == 2:
if dealer_cards[0].card_value == 11 and dealer_cards[1].card_value == 11:
dealer_cards[1].card_value = 1
dealer_score -= 10
input()
clear()
# Print dealer and player cards
print("DEALER CARDS: ")
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
print()
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
# Managing the player moves
while player_score < 21:
choice = input("Enter H to Hit or S to Stand : ")
# Sanity checks for player's choice
if len(choice) != 1 or (choice.upper() != 'H' and choice.upper() != 'S'):
clear()
print("Wrong choice!! Try Again")
# If player decides to HIT
if choice.upper() == 'H':
# Dealing a new card
player_card = random.choice(deck)
player_cards.append(player_card)
deck.remove(player_card)
# Updating player score
player_score += player_card.card_value
# Updating player score in case player's card have ace in them
c = 0
while player_score > 21 and c < len(player_cards):
if player_cards[c].card_value == 11:
player_cards[c].card_value = 1
player_score -= 10
c += 1
else:
c += 1
clear()
# Print player and dealer cards
print("DEALER CARDS: ")
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
print()
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
# If player decides to Stand
if choice.upper() == 'S':
break
clear()
# Print player and dealer cards
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
print()
print("DEALER IS REVEALING THE CARDS....")
print("DEALER CARDS: ")
print_cards(dealer_cards, False)
print("DEALER SCORE = ", dealer_score)
# Check if player has a Blackjack
if player_score == 21:
print("PLAYER HAS A BLACKJACK")
blackjacks += 1
# Check if player busts
if player_score > 21:
print("PLAYER BUSTED!!!")
busts += 1
print("DEALER WINS!!!")
losses += 1
funds -= bet
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
input()
# Managing the dealer moves
while dealer_score < 17:
clear()
print("DEALER DECIDES TO HIT.....")
# Dealing card for dealer
dealer_card = random.choice(deck)
dealer_cards.append(dealer_card)
deck.remove(dealer_card)
# Updating the dealer's score
dealer_score += dealer_card.card_value
# Updating player score in case player's card have ace in them
c = 0
while dealer_score > 21 and c < len(dealer_cards):
if dealer_cards[c].card_value == 11:
dealer_cards[c].card_value = 1
dealer_score -= 10
c += 1
else:
c += 1
# print player and dealer cards
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
print()
print("DEALER CARDS: ")
print_cards(dealer_cards, False)
print("DEALER SCORE = ", dealer_score)
input()
# TIE Game
if dealer_score == player_score:
print("TIE GAME!!!!")
ties += 1
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
# Dealer busts
elif dealer_score > 21:
print("DEALER BUSTED!!! YOU WIN!!!")
wins += 1
funds += bet
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
# Dealer gets a blackjack
elif dealer_score == 21:
print("DEALER HAS A BLACKJACK!!! PLAYER LOSES")
losses += 1
funds -= bet
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
# Player Wins
elif player_score < 21 and player_score > dealer_score:
print("PLAYER WINS!!!")
wins += 1
funds += bet
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
# Dealer Wins
else:
print("DEALER WINS!!!")
losses += 1
funds -= bet
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
quit()
if __name__ == '__main__':
# The type of suit
suits = ["Spades", "Hearts", "Clubs", "Diamonds"]
# The suit value
suits_values = {"Spades":"u2664", "Hearts":"u2661", "Clubs": "u2667", "Diamonds": "u2662"}
# The type of card
cards = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
# The card value
cards_values = {"A": 11, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, "10":10, "J":10, "Q":10, "K":10}
# The deck of cards
deck = []
# Loop for every type of suit
for suit in suits:
# Loop for every type of card in a suit
for card in cards:
# Adding card to the deck
deck.append(Card(suits_values[suit], card, cards_values[card]))
I added a quit() that should trigger should ‘while play_again == ‘Y’:’ no longer be true. This should have quit the game and stopped it from running. Instead it prompts the user again for a betting amount, acting as if I chose ‘Y’ instead.
I also tried removing:
play_again = 'Y'
and replacing this code block:
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
with this:
end_choice = input('Play again(Y/N)?: ')
if end_choice.upper() == 'N':
exit()
But it still wouldn’t quit and stayed as an infinite loop. Help me please, I’ve been stuck with this issue all day.
Answers:
Can you please try by replacing from this:
# Bets
while play_again == 'Y':
while end_game == False:
while funds > 0:
while bet == 0:
bet = int(input('Enter bet amount: '))
if bet > funds:
print('Insufficient funds')
bet = 0
With
# Bets
while play_again == 'Y':
while end_game == False:
if play_again != 'Y':
break
while funds > 0:
if play_again != 'Y' or end_game:
break
while bet == 0:
bet = int(input('Enter bet amount: '))
if bet > funds:
print('Insufficient funds')
bet = 0
I believe we don’t even need to add end_game
as it is unnecessary in current scope.
These are nested while loop and parent while loop will not break until child breaks. so we need to add extra condition in child while loop which break it on the basis of parent check.
you can read this post 5 Ways To Break Out of Nested Loops in Python
So the issue (to Usman’s point) really comes from the nesting levels. Basically for the below logic, it will only check if play_again is still True once end_game is False, which it will only check once funds is no longer > 0.
while play_again == 'Y':
while end_game == False:
while funds > 0:
while bet == 0:
...
play_again = input("Play again?")
Your code would actually work fine if you had the proper indentation (end of loop being within the "play_again" or "end_game" levels), but unless there’s a really good reason, it’s typically better to combine conditionals rather than nesting them in multiple while loops that are easy to lose track of. Consider instead:
while (play_again == "Y") and (funds > 0):
if bet == 0:
bet = int(input('Enter bet amount: '))
if bet < self.funds:
print("Insufficient funds")
...
Other Notes
Based on the coding style it seems like you’re at the start of your wonderful journey into Python, and I wanted to pay forward the help I got starting out by giving some (hopefully) useful tips in case this wasn’t part of a structured course. I wound up slapping together an MVP for how this might look below (can build further), please read through the notes though additionally:
- Break apart large functions! It’ll make your life a lot easier, this looks to be maybe an initial project and you get a better knack for where to break things up as you move along, but a single function being ~300 lines is just going to make you miserable. General rule of thumb to have maybe 40-50 lines max unless there’s a really good reason.
- Utilize classes more (especially if you’re trying to be OOP!), a "BlackjackGame" class could help keep methods and attributes organized vs having to set them only once per iteration, and helps keep track of variables across games (i.e. total value).
- Type hinting to make your life easier. Depending on where you are in your learning path this might be a bit later on, but it makes things infinitely easier for working with Intellisense hints (see below using Pylance in VSCode). You could also just create a Deck class itself.
Sample
import itertools
import random
import os
from typing import List, Literal
def clear():
os.system("clear")
class BlackjackRound:
def __init__(self, deck):
self.player_hand: Hand = Hand()
self.dealer_hand: Hand = Hand()
self.deck: List[Card] = deck
## Draw top cards
for hand in [self.player_hand, self.dealer_hand]:
for _ in range(2):
self.deck = hand.draw(self.deck)
self._print_stats()
while self.player_hand.value < 21:
choice = input("Enter H to Hit or S to Stand : ")
if len(choice) != 1 or (choice.upper() != 'H' and choice.upper() != 'S'):
clear()
print("Wrong choice!! Try Again")
continue
if choice.upper() == 'H':
self.deck = self.player_hand.draw(self.deck)
if choice.upper() == 'S':
break
self._print_stats()
## Resolve Dealer Hand
self._print_stats(mask_dealer=False)
while self.dealer_hand.value < 17:
print("Dealer draws...")
self.deck = self.dealer_hand.draw(self.deck)
self._print_stats(mask_dealer=False)
##For dramatic tension
if self.dealer_hand.value < 17:
input("Enter to continue...")
def _print_stats(self, mask_dealer=True):
print("You're hand")
self.player_hand.print_cards()
print(f"PLAYER SCORE = {self.player_hand.value}")
print("Dealer showing...")
if mask_dealer:
self.dealer_hand.print_cards(hidden=True, n_cards=1)
print(f"DEALER SCORE = {self.dealer_hand.cards[0].card_value}")
else:
self.dealer_hand.print_cards()
print(f"DEALER SCORE = {self.dealer_hand.value}")
# The Card class definition
class Card:
def __init__(self, suit, value, card_value, suit_format):
# Suit of the Card like Spades and Clubs
self.suit = suit
# Representing Value of the Card like A for Ace, K for King
self.value = value
# Score Value for the Card like 10 for King
self.card_value = card_value
self.suit_format = suit_format
#How should Card be printed?
def __repr__(self):
return str(self.__dict__)
class Hand:
def __init__(self):
self.cards: List[Card] = []
self.value = 0
def draw(self, deck: List[Card]):
player_card = random.choice(deck)
self.cards.append(player_card)
deck.remove(player_card)
self.value += player_card.card_value
self.revalue_ace()
return deck
def revalue_ace(self):
##Sum greater than 21,
if (self.value > 21) and ("A" in [card.value for card in self.cards]):
swap_card = list(filter(lambda x: x.value == "A", self.cards))[0]
self.cards[self.cards.index(swap_card)].card_value = 1
self.value-=10
else:
pass
def print_cards(self, hidden: bool=False, n_cards=None):
s = ""
cards = self.cards if n_cards is None else self.cards[0:n_cards]
for card in cards:
s = s + "t ________________"
if hidden:
s += "t ________________"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + "t| {} |".format(card.value)
else:
s = s + "t| {} |".format(card.value)
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| {} |".format(card.suit_format)
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + "t| {} |".format(card.value)
else:
s = s + "t| {} |".format(card.value)
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t|________________|"
if hidden:
s += "t|________________|"
print(s)
print()
class BlackjackGame:
def __init__(self):
##play_again can only be Y/N
self.play_again: Literal["Y", "N"] = "Y"
self.player_name: str = input("Player name?: ")
self.funds = 100
self.wins = 0
self.losses = 0
self.ties = 0
self.blackjacks = 0
self.busts = 0
def _print_stats(self):
print(f"Current funds: {self.funds}")
def play_game(self):
self._print_stats
self.shuffle_deck()
bet = 0
while (self.play_again == "Y") and (self.funds > 0):
if bet == 0:
bet = int(input('Enter bet amount: '))
if bet < self.funds:
print("Insufficient funds")
continue #Restart at the top of the key
round = BlackjackRound(self.deck)
if round.player_hand.value == 21:
print("Blackjack!")
self.blackjacks+=1
self.funds+=bet
elif round.player_hand.value > 21:
print("BUST")
self.busts+=1
self.funds-=bet
elif round.dealer_hand.value > 21:
print("DEALER BUST!")
self.wins +=1
self.funds+=bet
elif round.player_hand.value > round.dealer_hand.value:
print("Win!")
self.wins+=1
self.funds+=bet
elif round.player_hand.value < round.dealer_hand.value:
print("Lose!")
self.losses+=1
self.funds-=bet
else:
print("Tie!")
self.ties+=1
## Error handling for exit
bet=0
##Update deck from round
self.deck = round.deck
while True:
self.play_again = input('Play again(Y/N)?: ')
if self.play_again == "N":
print("So long!")
quit()
elif self.funds == 0:
print("Too bad, you're broke!")
quit()
elif self.play_again == "Y":
print("Around we go!")
print("Try again plz")
def shuffle_deck(self,
suits = {"Spades":"u2664", "Hearts":"u2661", "Clubs": "u2667", "Diamonds": "u2662"},
cards = {"A": 11, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, "10":10, "J":10, "Q":10, "K":10}
):
"""
Create a deck of 52 cards
"""
self.deck = [Card(combo[0], combo[1], cards[combo[1]], suits[combo[0]]) for combo in itertools.product(suits.keys(), cards.keys())]
if __name__ == '__main__':
bg = BlackjackGame()
bg.play_game()
I made a code for Blackjack in Python and whenever I run blackjack_game(deck) saying no to the ‘Play Again’ input should quit the game but it doesn’t. Funds going zero and below should also trigger the game to quit but it doesn’t.
This is what it looks like:
import random
import os
# The Card class definition
class Card:
def __init__(self, suit, value, card_value):
# Suit of the Card like Spades and Clubs
self.suit = suit
# Representing Value of the Card like A for Ace, K for King
self.value = value
# Score Value for the Card like 10 for King
self.card_value = card_value
# Clear the terminal
def clear():
os.system("clear")
# Print player stats
def print_stats(player_name, funds, wins, losses, ties, blackjacks, busts):
print('Player: ', player_name)
print('Funds: $', funds)
print(f'Wins: {wins} Losses: {losses} Ties: {ties} Blackjacks: {blackjacks} Busts: {busts}')
# Function to print the cards
def print_cards(cards, hidden):
s = ""
for card in cards:
s = s + "t ________________"
if hidden:
s += "t ________________"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + "t| {} |".format(card.value)
else:
s = s + "t| {} |".format(card.value)
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| {} |".format(card.suit)
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + "t| {} |".format(card.value)
else:
s = s + "t| {} |".format(card.value)
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t|________________|"
if hidden:
s += "t|________________|"
print(s)
print()
# Function for a game of blackjack
def blackjack_game(deck):
end_game = False
play_again = 'Y'
# Player name
player_name = str(input('Enter player name: '))
# Intro
print('Lets have a fun game of Blackjack, ', player_name)
# Cards for both dealer and player
player_cards = []
dealer_cards = []
# Scores for both dealer and player
player_score = 0
dealer_score = 0
# Player stats
funds = 100
wins = 0
losses = 0
ties = 0
blackjacks = 0
busts = 0
bet = 0
clear()
# Current Stats Display
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
# Bets
while play_again == 'Y':
while end_game == False:
while funds > 0:
while bet == 0:
bet = int(input('Enter bet amount: '))
if bet > funds:
print('Insufficient funds')
bet = 0
# Initial dealing for player and dealer
while len(player_cards) < 2:
# Randomly dealing a card
player_card = random.choice(deck)
player_cards.append(player_card)
deck.remove(player_card)
# Updating the player score
player_score += player_card.card_value
# In case both the cards are Ace, make the first ace value as 1
if len(player_cards) == 2:
if player_cards[0].card_value == 11 and player_cards[1].card_value == 11:
player_cards[0].card_value = 1
player_score -= 10
# Print player cards and score
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
input()
# Randomly dealing a card
dealer_card = random.choice(deck)
dealer_cards.append(dealer_card)
deck.remove(dealer_card)
# Updating the dealer score
dealer_score += dealer_card.card_value
# Print dealer cards and score, keeping in mind to hide the second card and score
print("DEALER CARDS: ")
if len(dealer_cards) == 1:
print_cards(dealer_cards, False)
print("DEALER SCORE = ", dealer_score)
else:
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
# In case both the cards are Ace, make the second ace value as 1
if len(dealer_cards) == 2:
if dealer_cards[0].card_value == 11 and dealer_cards[1].card_value == 11:
dealer_cards[1].card_value = 1
dealer_score -= 10
input()
clear()
# Print dealer and player cards
print("DEALER CARDS: ")
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
print()
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
# Managing the player moves
while player_score < 21:
choice = input("Enter H to Hit or S to Stand : ")
# Sanity checks for player's choice
if len(choice) != 1 or (choice.upper() != 'H' and choice.upper() != 'S'):
clear()
print("Wrong choice!! Try Again")
# If player decides to HIT
if choice.upper() == 'H':
# Dealing a new card
player_card = random.choice(deck)
player_cards.append(player_card)
deck.remove(player_card)
# Updating player score
player_score += player_card.card_value
# Updating player score in case player's card have ace in them
c = 0
while player_score > 21 and c < len(player_cards):
if player_cards[c].card_value == 11:
player_cards[c].card_value = 1
player_score -= 10
c += 1
else:
c += 1
clear()
# Print player and dealer cards
print("DEALER CARDS: ")
print_cards(dealer_cards[:-1], True)
print("DEALER SCORE = ", dealer_score - dealer_cards[-1].card_value)
print()
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
# If player decides to Stand
if choice.upper() == 'S':
break
clear()
# Print player and dealer cards
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
print()
print("DEALER IS REVEALING THE CARDS....")
print("DEALER CARDS: ")
print_cards(dealer_cards, False)
print("DEALER SCORE = ", dealer_score)
# Check if player has a Blackjack
if player_score == 21:
print("PLAYER HAS A BLACKJACK")
blackjacks += 1
# Check if player busts
if player_score > 21:
print("PLAYER BUSTED!!!")
busts += 1
print("DEALER WINS!!!")
losses += 1
funds -= bet
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
input()
# Managing the dealer moves
while dealer_score < 17:
clear()
print("DEALER DECIDES TO HIT.....")
# Dealing card for dealer
dealer_card = random.choice(deck)
dealer_cards.append(dealer_card)
deck.remove(dealer_card)
# Updating the dealer's score
dealer_score += dealer_card.card_value
# Updating player score in case player's card have ace in them
c = 0
while dealer_score > 21 and c < len(dealer_cards):
if dealer_cards[c].card_value == 11:
dealer_cards[c].card_value = 1
dealer_score -= 10
c += 1
else:
c += 1
# print player and dealer cards
print("PLAYER CARDS: ")
print_cards(player_cards, False)
print("PLAYER SCORE = ", player_score)
print()
print("DEALER CARDS: ")
print_cards(dealer_cards, False)
print("DEALER SCORE = ", dealer_score)
input()
# TIE Game
if dealer_score == player_score:
print("TIE GAME!!!!")
ties += 1
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
# Dealer busts
elif dealer_score > 21:
print("DEALER BUSTED!!! YOU WIN!!!")
wins += 1
funds += bet
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
# Dealer gets a blackjack
elif dealer_score == 21:
print("DEALER HAS A BLACKJACK!!! PLAYER LOSES")
losses += 1
funds -= bet
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
# Player Wins
elif player_score < 21 and player_score > dealer_score:
print("PLAYER WINS!!!")
wins += 1
funds += bet
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
# Dealer Wins
else:
print("DEALER WINS!!!")
losses += 1
funds -= bet
bet = 0
print_stats(player_name, funds, wins, losses, ties, blackjacks, busts)
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
player_cards = []
dealer_cards = []
player_score = 0
dealer_score = 0
end_game = True
quit()
if __name__ == '__main__':
# The type of suit
suits = ["Spades", "Hearts", "Clubs", "Diamonds"]
# The suit value
suits_values = {"Spades":"u2664", "Hearts":"u2661", "Clubs": "u2667", "Diamonds": "u2662"}
# The type of card
cards = ["A", "2", "3", "4", "5", "6", "7", "8", "9", "10", "J", "Q", "K"]
# The card value
cards_values = {"A": 11, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, "10":10, "J":10, "Q":10, "K":10}
# The deck of cards
deck = []
# Loop for every type of suit
for suit in suits:
# Loop for every type of card in a suit
for card in cards:
# Adding card to the deck
deck.append(Card(suits_values[suit], card, cards_values[card]))
I added a quit() that should trigger should ‘while play_again == ‘Y’:’ no longer be true. This should have quit the game and stopped it from running. Instead it prompts the user again for a betting amount, acting as if I chose ‘Y’ instead.
I also tried removing:
play_again = 'Y'
and replacing this code block:
end_choice = input('Play again(Y/N)?: ')
play_again = end_choice.upper()
with this:
end_choice = input('Play again(Y/N)?: ')
if end_choice.upper() == 'N':
exit()
But it still wouldn’t quit and stayed as an infinite loop. Help me please, I’ve been stuck with this issue all day.
Can you please try by replacing from this:
# Bets
while play_again == 'Y':
while end_game == False:
while funds > 0:
while bet == 0:
bet = int(input('Enter bet amount: '))
if bet > funds:
print('Insufficient funds')
bet = 0
With
# Bets
while play_again == 'Y':
while end_game == False:
if play_again != 'Y':
break
while funds > 0:
if play_again != 'Y' or end_game:
break
while bet == 0:
bet = int(input('Enter bet amount: '))
if bet > funds:
print('Insufficient funds')
bet = 0
I believe we don’t even need to add end_game
as it is unnecessary in current scope.
These are nested while loop and parent while loop will not break until child breaks. so we need to add extra condition in child while loop which break it on the basis of parent check.
you can read this post 5 Ways To Break Out of Nested Loops in Python
So the issue (to Usman’s point) really comes from the nesting levels. Basically for the below logic, it will only check if play_again is still True once end_game is False, which it will only check once funds is no longer > 0.
while play_again == 'Y':
while end_game == False:
while funds > 0:
while bet == 0:
...
play_again = input("Play again?")
Your code would actually work fine if you had the proper indentation (end of loop being within the "play_again" or "end_game" levels), but unless there’s a really good reason, it’s typically better to combine conditionals rather than nesting them in multiple while loops that are easy to lose track of. Consider instead:
while (play_again == "Y") and (funds > 0):
if bet == 0:
bet = int(input('Enter bet amount: '))
if bet < self.funds:
print("Insufficient funds")
...
Other Notes
Based on the coding style it seems like you’re at the start of your wonderful journey into Python, and I wanted to pay forward the help I got starting out by giving some (hopefully) useful tips in case this wasn’t part of a structured course. I wound up slapping together an MVP for how this might look below (can build further), please read through the notes though additionally:
- Break apart large functions! It’ll make your life a lot easier, this looks to be maybe an initial project and you get a better knack for where to break things up as you move along, but a single function being ~300 lines is just going to make you miserable. General rule of thumb to have maybe 40-50 lines max unless there’s a really good reason.
- Utilize classes more (especially if you’re trying to be OOP!), a "BlackjackGame" class could help keep methods and attributes organized vs having to set them only once per iteration, and helps keep track of variables across games (i.e. total value).
- Type hinting to make your life easier. Depending on where you are in your learning path this might be a bit later on, but it makes things infinitely easier for working with Intellisense hints (see below using Pylance in VSCode). You could also just create a Deck class itself.
Sample
import itertools
import random
import os
from typing import List, Literal
def clear():
os.system("clear")
class BlackjackRound:
def __init__(self, deck):
self.player_hand: Hand = Hand()
self.dealer_hand: Hand = Hand()
self.deck: List[Card] = deck
## Draw top cards
for hand in [self.player_hand, self.dealer_hand]:
for _ in range(2):
self.deck = hand.draw(self.deck)
self._print_stats()
while self.player_hand.value < 21:
choice = input("Enter H to Hit or S to Stand : ")
if len(choice) != 1 or (choice.upper() != 'H' and choice.upper() != 'S'):
clear()
print("Wrong choice!! Try Again")
continue
if choice.upper() == 'H':
self.deck = self.player_hand.draw(self.deck)
if choice.upper() == 'S':
break
self._print_stats()
## Resolve Dealer Hand
self._print_stats(mask_dealer=False)
while self.dealer_hand.value < 17:
print("Dealer draws...")
self.deck = self.dealer_hand.draw(self.deck)
self._print_stats(mask_dealer=False)
##For dramatic tension
if self.dealer_hand.value < 17:
input("Enter to continue...")
def _print_stats(self, mask_dealer=True):
print("You're hand")
self.player_hand.print_cards()
print(f"PLAYER SCORE = {self.player_hand.value}")
print("Dealer showing...")
if mask_dealer:
self.dealer_hand.print_cards(hidden=True, n_cards=1)
print(f"DEALER SCORE = {self.dealer_hand.cards[0].card_value}")
else:
self.dealer_hand.print_cards()
print(f"DEALER SCORE = {self.dealer_hand.value}")
# The Card class definition
class Card:
def __init__(self, suit, value, card_value, suit_format):
# Suit of the Card like Spades and Clubs
self.suit = suit
# Representing Value of the Card like A for Ace, K for King
self.value = value
# Score Value for the Card like 10 for King
self.card_value = card_value
self.suit_format = suit_format
#How should Card be printed?
def __repr__(self):
return str(self.__dict__)
class Hand:
def __init__(self):
self.cards: List[Card] = []
self.value = 0
def draw(self, deck: List[Card]):
player_card = random.choice(deck)
self.cards.append(player_card)
deck.remove(player_card)
self.value += player_card.card_value
self.revalue_ace()
return deck
def revalue_ace(self):
##Sum greater than 21,
if (self.value > 21) and ("A" in [card.value for card in self.cards]):
swap_card = list(filter(lambda x: x.value == "A", self.cards))[0]
self.cards[self.cards.index(swap_card)].card_value = 1
self.value-=10
else:
pass
def print_cards(self, hidden: bool=False, n_cards=None):
s = ""
cards = self.cards if n_cards is None else self.cards[0:n_cards]
for card in cards:
s = s + "t ________________"
if hidden:
s += "t ________________"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + "t| {} |".format(card.value)
else:
s = s + "t| {} |".format(card.value)
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * * |"
print(s)
s = ""
for card in cards:
s = s + "t| {} |".format(card.suit_format)
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
s = s + "t| |"
if hidden:
s += "t| |"
print(s)
s = ""
for card in cards:
if card.value == '10':
s = s + "t| {} |".format(card.value)
else:
s = s + "t| {} |".format(card.value)
if hidden:
s += "t| * |"
print(s)
s = ""
for card in cards:
s = s + "t|________________|"
if hidden:
s += "t|________________|"
print(s)
print()
class BlackjackGame:
def __init__(self):
##play_again can only be Y/N
self.play_again: Literal["Y", "N"] = "Y"
self.player_name: str = input("Player name?: ")
self.funds = 100
self.wins = 0
self.losses = 0
self.ties = 0
self.blackjacks = 0
self.busts = 0
def _print_stats(self):
print(f"Current funds: {self.funds}")
def play_game(self):
self._print_stats
self.shuffle_deck()
bet = 0
while (self.play_again == "Y") and (self.funds > 0):
if bet == 0:
bet = int(input('Enter bet amount: '))
if bet < self.funds:
print("Insufficient funds")
continue #Restart at the top of the key
round = BlackjackRound(self.deck)
if round.player_hand.value == 21:
print("Blackjack!")
self.blackjacks+=1
self.funds+=bet
elif round.player_hand.value > 21:
print("BUST")
self.busts+=1
self.funds-=bet
elif round.dealer_hand.value > 21:
print("DEALER BUST!")
self.wins +=1
self.funds+=bet
elif round.player_hand.value > round.dealer_hand.value:
print("Win!")
self.wins+=1
self.funds+=bet
elif round.player_hand.value < round.dealer_hand.value:
print("Lose!")
self.losses+=1
self.funds-=bet
else:
print("Tie!")
self.ties+=1
## Error handling for exit
bet=0
##Update deck from round
self.deck = round.deck
while True:
self.play_again = input('Play again(Y/N)?: ')
if self.play_again == "N":
print("So long!")
quit()
elif self.funds == 0:
print("Too bad, you're broke!")
quit()
elif self.play_again == "Y":
print("Around we go!")
print("Try again plz")
def shuffle_deck(self,
suits = {"Spades":"u2664", "Hearts":"u2661", "Clubs": "u2667", "Diamonds": "u2662"},
cards = {"A": 11, "2":2, "3":3, "4":4, "5":5, "6":6, "7":7, "8":8, "9":9, "10":10, "J":10, "Q":10, "K":10}
):
"""
Create a deck of 52 cards
"""
self.deck = [Card(combo[0], combo[1], cards[combo[1]], suits[combo[0]]) for combo in itertools.product(suits.keys(), cards.keys())]
if __name__ == '__main__':
bg = BlackjackGame()
bg.play_game()