I am writing a (simple) blackjack game, and I'm using the following code to give the user the option to play again until they decide they don't want to anymore.
while True:
game()
if "n" in input("Do you want to play again? Y or N").lower():
break
The issue is I have several exit() in nested functions in game() designed to stop the game prematurely (i.e. natural blackjack from the start, or a bust). But I find that exit() terminates the whole script, and also skips the above piece of code altogether.
I can't use return or break in those nested functions within the game() because I find that return/break only exits the nested functions, but the game() still continues, even if I want the game() to stop. I have the following example:
def game():
def first_check():
player_sum = sum(player)
dealer_sum = sum(dealer)
if 21 in [player_sum,dealer_sum]:
if 21 in [player_sum] and 21 in [dealer_sum]:
print("Both you and the dealer have Blackjack, its a push!!")
blackjack()
exit()
if I use break instead of exit() in the above first_check(), its exits out of first_check(), but the game() still runs even though I want it to stop.
Is there any function or statement that exits the overarching function it is in, without killing the whole script?
Thank you!
Tried return and break but they don't achieve what I want.
I tried putting the nested functions outside of game() but the game() still runs when I want it to stop.
You could define a custom exception that you can throw and then wrap your call to game
in a try-catch, followed by the prompt to check if they would like to play again.
Define your exception:
class StopGameIteration(Exception):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
Rewrite your game()
function to use your exception:
def game():
def first_check():
player_sum = sum(player)
dealer_sum = sum(dealer)
if 21 in [player_sum,dealer_sum]:
if 21 in [player_sum] and 21 in [dealer_sum]:
print("Both you and the dealer have Blackjack, its a push!!")
blackjack()
raise StopGameIteration("Had blackjack")
and wrap your call in try catch:
while True:
try:
game()
except StopGameIteration:
pass
if "n" in input("Do you want to play again? Y or N").lower():
break
You could even create several exceptions so that you can adjust behavior based on why you broke out of your function:
class GameException(Exception):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class BlackjackAchieved(GameException):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
class PlayerCheated(GameException):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
and then respond accordingly:
while True:
try:
game()
except BlackjackAchieved:
print("Someone got a blackjack")
except PlayerCheated:
print("oh no, someone cheated")
except GameException:
print("Something related to the game happened to cause it to quit")
if "n" in input("Do you want to play again? Y or N").lower():
break
EDIT: @pranav-hosangadi makes a good point: the try-catch should probably be inside the game
function so that the logic for the game is fully self-contained. Then, in your finally
clause for the try-catch block, you could optionally use a return to break back to the outside loop.