If I have a text-based game, and I transition through game states by calling a function corresponding to each game state like the following
def go_to_lobby(gold_coins: int) -> None:
""" The start of the adventure """
print_gold_amount(gold_coins)
print("You are in the lobby of the dungeon. What do you do?")
print("1. Examine the lobby.")
print("2. Go to the throne hall.")
print("3. Leave.")
option = int(input())
if option==1:
examine_lobby(gold_coins)
elif option==2:
go_to_throne_hall(gold_coins)
else:
leave(gold_coins)
def examine_lobby(gold_coins: int) -> None:
""" The user examines the lobby """
print_gold_amount(gold_coins)
rob_amount = 10
print("A band of goblins rob " + str(rob_amount) + " gold from you.")
gold_coins-=rob_amount
go_to_lobby(gold_coins)
def leave(gold_coins: int) -> None:
""" The end of the adventure """
print_gold_amount(gold_coins)
if gold_coins<0:
go_to_kitchen(gold_coins)
else:
print("You leave the dungeon.")
def go_to_throne_hall(gold_coins: int) -> None:
""" The middle of the adventure """
print_gold_amount(gold_coins)
print("You are in the throne hall. What do you do?")
print("1. Examine the throne hall.")
print("2. Go back to the lobby.")
option = int(input())
if option==1:
examine_throne_hall(gold_coins)
else:
go_to_lobby(gold_coins)
def examine_throne_hall(gold_coins: int) -> None:
""" The user examines the throne hall """
print_gold_amount(gold_coins)
rob_amount = 40
print("You disturb the dungeon keeper who makes you pay " + str(rob_amount) + " gold.")
gold_coins-=rob_amount
go_to_throne_hall(gold_coins)
def print_gold_amount(gold_coins: int) -> None:
""" Prints to the user their current amount of gold """
print("You have " + str(gold_coins) + " gold.")
def go_to_kitchen(gold_coins: int) -> None:
print_gold_amount(gold_coins)
print("You are in the kitchen. What do you do?")
print("1. Wash the dishes to earn money.")
print("2. Enter the dungeon and go back to the lobby.")
option = int(input())
if option==1:
print("You washed the dishes and earnt a coin!")
go_to_kitchen(gold_coins)
else:
if gold_coins<0:
go_to_lobby(gold_coins-10)
else:
go_to_lobby(gold_coins)
go_to_lobby(50)
It will be memory inefficient (I think) because each function has to remember where it was when I started the new one. However this memory will never be useful to me because I am never going to return. Is there a way to make this approach memory efficient in Python or is it inherently going to have the memory issue? (I'm aware of how I could fix this issue, but I am wondering if there's a solution that still allows me to operate by jumping between functions, Python has a good garbage collector system so I thought there might be some way to do it.)
Like @Joffan pointed out in the comment, you should convert your recursive program flow to an iterative one with an action loop where each action sets the next action to perform.
Without rewriting your code, however, you can perform the conversion by applying to each action function a decorator that defers a call to the function to an action loop that will perform it in the next iteration.
The loop can be implicitly kicked off by the first call to an action function, which can be identified by setting the initial next action as None
. The loop ends when an action does not set the next action, when the next action after a call remains the same:
class action:
next = None
def __init__(self, func):
self.func = func
def __call__(self, *args, **kwargs):
loop = action.next is None
action.next = lambda: self.func(*args, **kwargs)
while loop:
current_action = action.next
current_action()
if action.next is current_action:
break
Below is your exact same code with just the @action
decorator applied (and with washing dishes in the kitchen earning you 40 coins instead so you can actually leave once in debt, for a bug pointed out by @trincot):
@action
def go_to_lobby(gold_coins: int) -> None:
""" The start of the adventure """
print_gold_amount(gold_coins)
print("You are in the lobby of the dungeon. What do you do?")
print("1. Examine the lobby.")
print("2. Go to the throne hall.")
print("3. Leave.")
option = int(input())
if option==1:
examine_lobby(gold_coins)
elif option==2:
go_to_throne_hall(gold_coins)
else:
leave(gold_coins)
@action
def examine_lobby(gold_coins: int) -> None:
""" The user examines the lobby """
print_gold_amount(gold_coins)
rob_amount = 10
print("A band of goblins rob " + str(rob_amount) + " gold from you.")
gold_coins-=rob_amount
go_to_lobby(gold_coins)
@action
def leave(gold_coins: int) -> None:
""" The end of the adventure """
print_gold_amount(gold_coins)
if gold_coins<0:
go_to_kitchen(gold_coins)
else:
print("You leave the dungeon.")
@action
def go_to_throne_hall(gold_coins: int) -> None:
""" The middle of the adventure """
print_gold_amount(gold_coins)
print("You are in the throne hall. What do you do?")
print("1. Examine the throne hall.")
print("2. Go back to the lobby.")
option = int(input())
if option==1:
examine_throne_hall(gold_coins)
else:
go_to_lobby(gold_coins)
@action
def examine_throne_hall(gold_coins: int) -> None:
""" The user examines the throne hall """
print_gold_amount(gold_coins)
rob_amount = 40
print("You disturb the dungeon keeper who makes you pay " + str(rob_amount) + " gold.")
gold_coins-=rob_amount
go_to_throne_hall(gold_coins)
def print_gold_amount(gold_coins: int) -> None:
""" Prints to the user their current amount of gold """
print("You have " + str(gold_coins) + " gold.")
@action
def go_to_kitchen(gold_coins: int) -> None:
print_gold_amount(gold_coins)
print("You are in the kitchen. What do you do?")
print("1. Wash the dishes to earn money.")
print("2. Enter the dungeon and go back to the lobby.")
option = int(input())
if option==1:
print("You washed the dishes and earnt a coin!")
go_to_kitchen(gold_coins+40)
else:
if gold_coins<0:
go_to_lobby(gold_coins-10)
else:
go_to_lobby(gold_coins)
go_to_lobby(50)