I'm starting a rudimentary text adventure game. I got a prototype working, but because each choice is a function, I can't figure out how to safely save my place in a file.
I considered saving the function's name to a file, but I can't think of a good way to get the function from its name as a str
after reading the file. eval
on an arbitrary str
is notoriously unsafe. I considered a dict
mapping every function to its name as a str
, but it seems that as more choices pile up, this dict
is gonna bloat my script.
def choice1():
while True:
text = input("A or B?: ")
if text == "A":
return False, choice2
elif text == "B":
saygameover()
return True, None
elif askedforsave(text):
return True, choice1
else:
saytryagain()
def choice2():
while True:
text = input("C or D?: ")
if text == "C":
print("you win!")
return True, None
elif text == "D":
saygameover()
return True, None
elif askedforsave(text):
return True, choice2
else:
saytryagain()
def askedforsave(text):
if text == "save":
return True
else:
return False
def saytryagain():
print("try again...")
def saygameover():
print("game over.")
def play(choice = choice1):
done = False
while not done:
done, choice = choice()
if choice != None:
save(choice)
def save(choice):
pass
def load(file):
pass
return choice
This is what I got so far. isidentifier
is probably unnecessary when I'm already checking for a name in globals()
but it's a good trick for making sure you're working with a valid Python name instead of an expression.
import types
def load(string):
# if string is valid Python name
if (string.isidentifier() and
# if string in this global scope's symbol table
string in (thisglobal := globals()) and
# if object is a non-builtin function
isinstance(something := thisglobal[string], types.FunctionType)):
return something
else:
return nogame
def nogame():
return True, None