So, finally I'm getting to the end of LPTHW, and I'm creating my own text adventure type of game.
I want to incorporate a save function to the game (probably by using file write). Also, the game can give you hints based on your location in the game. What I basically need is following:
There will be lots of prompts for user input (raw_input) in while loops. I want to be able to type SAVE or HINT any time to trigger a function. How do I do this so I don't have to create the same conditional every time? (for example elif action == "HINT": print "...")
Is there a way to create some global expressions so that every time they're typed in the prompt, I can act on them? I will create a module with a dictionary that will reference a certain hint when the player is present in a certain location. I just want to avoid putting the same conditionals all over the place.
If you separate the input into a function, you can pass a hint and access save easily:
def user_input(prompt, hint):
while True:
ui = raw_input(prompt)
if ui.lower() == "hint":
print hint
elif ui.lower() == "save":
save()
else:
return ui
You could also add checking here that the user stays within specific choices (an additional argument), deal with any errors and only ever return valid input.
you should probably use a dictionary
def do_save(*args,**kwargs):
print "SAVE!"
def do_hint(*args,**kwargs):
print "HINT!"
def do_quit(*args,**kwargs):
print "OK EXIT!"
global_actions = {'SAVE':do_save,
'HINT':do_hint,
'QUIT':do_quit}
def go_north(*args,**kwargs):
print "You Go North"
def go_east(*args,**kwargs):
print "you go east"
def make_choice(prompt="ENTER COMMAND:",actions={},context_info={}):
choice = raw_input(prompt)
fn = actions.get(choice.upper(),lambda *a,**kw:sys.stdout.write("UNKOWN CHOICE!"))
return fn(some_context=context_info)
local_actions = {"NORTH":go_north,"EAST":go_east}
player_actions = dict(global_actions.items() + local_actions.items())
print "From Here You Can Go [North] or [East]"
result = make_choice(actions=player_actions,
context_info={"location":"narnia","player_level":5})
I don't know about the save feature but for hint you could just have;
If raw_input == hint:
print "whatever you want here"
Or if you need the hint to be different depending on your position you could have a variable for what the hint for that room is and have it update each time you enter a new room then have:
if raw_input == "hint":
print hintvariable
If this doesn't work then sorry, I'm new.
Related
I am attempting to create a game menu that I can then use in games to skip having to make a new menu each time. However, currently it just preforms the gameMain() function instead of doing the gameMenu() first, and then trying to select the game with "g" or "G" does nothing but end the program.
What I'm asking is if it's possible to have a variable in a module that's a function in the code that's importing it.
Here is the code for the menu, which is called textbasedadventures.py:
def gameMenu(game,your_choice="Please Enter how you'd like the game described"):
menu_options = ""
while not(menu_options == "G" or menu_options == "g":
title()
print()
print("\t\t",your_choice,"\n\n")
print('G start game')
menu_options = input("\t\tChoice: ")
if menu_options == "G" or menu_options == "g":
game
input(pause)
and this is the code for the game:
import sys
sys.path.append("\MyOwnProjects")
import textbasedadventures as t
def veryStart():
answer = ""
while not(answer == "1" or answer == "2" or answer == "3"):
print("\tYou are awoken by the blaring of your alarm clock.How did you sleep last night?")
print("\n\t1 Very well\n\n\t2 Well\n\n\t3 Not good\n\n\t4 atrociously")
answer = input("You slept ")
if answer == "1":
print("one option")
elif answer == "2":
print("\t")
elif answer == "3":
pass
elif answer == "4":
print("another option")
else:
print("\t",answer,"is not a valid entry, please try again")
def gameMain():
veryStart()
t.gameMenu(gameMain(),"please work")
If anyone can tell me how to do this, or if this is even possible, I'd be very grateful.
Your remaining problem is getting used to when you're calling a function, and when you're referring to the function as an object.
Since you didn't get any errors when you imported your textbasedadventures (which I shortened to tba to avoid typos), I assume that you've handled that properly: the file is named textbasedadventures.py and is in the local directory.
I had to remove the input(pause) line, since you didn't define pause, and it's there for a different shell from the one I'm using. I also had to remove title(), since that's no longer in your code.
When you pass the main program's main-game function, you have to pass it as a function object. You did this:
t.gameMenu(gameMain(),"please work")
This calls gameMain (because of the parentheses), grabs the return value, and passes that to t.gameMenu. Since there isn't any such return value, your remote menu routien receives only the value None.
Simply remove the parentheses:
t.gameMenu(gameMain,"please work")
This takes the entire gameMain function (well, a reference to it) and passes that to your remote function, where ...
Instead of calling the passed-in game module, you simply listed its value. Python thinks, "okay, cool, I have to evaluate this expression. Gee, a reference to an object -- that's easy. The value is simply the reference itself. I'm not even supposed to do anything with it. Done."
Simply putting a value on a line is legal Python, but boring: the value is displayed if you're in an interactive shell, but is otherwise ignored. Therefore, you never got any response from that line.
Instead, now you call it: this is where you put the parentheses you took off the other end of the call:
game()
I made those changes, and here's the result:
enter G to start game
Choice: g
You are awoken by the blaring of your alarm clock.How did you sleep last night?
1 Very well
2 Well
3 Not good
4 atrociously
You slept
I hope you're doing great! I would really appreciate if you help me with this problem of mine. I wrote this code that creates dictionary based on user's input, then updates it, sorts by keys and values, finds if the item is in the dictionary, counts the number of unique values and, finally, saves the original dictionary to the .txt file. The code itself works fine, but I wanted to present it as a menu so that user could choose what he/she would want to do next, but when I tried to just call the functions from the menu it didn't work and now I have no idea how to do it properly. Could you explain how I can do that? Thanks in advance!
1) Add a menu function, I only did the first three so that you can get the idea (you can do the rest of them), for example.
def menu():
print '1) Create a dictionary'
print '2) Update the dictionary'
print '3) Sort the dictionary'
task = raw_input('Enter the number to perform the corresponding task: ')
if task == '1':
user_dict = creating_dictionary()
elif task == '2':
try:
updating_dictionary(user_dict)
except UnboundLocalError:
print "A dictionary doesn't exist, you'll have to create one\n"
creating_dictionary()
elif task == '3':
try:
sorting_dictionary(user_dict)
except UnboundLocalError:
print "A dictionary doesn't exist, you'll have to create one\n"
creating_dictionary()
2) add menu() as your first statement in main()
3) at the end of every function add a call to menu()
4) If you set it up correctly then the only call you'll need in main() is menu(). You'll be able to delete all of the other function calls since at the end of every function you'll be calling menu().
So I'm trying to make a function that prompts the user for an option, and depending on which option it does something to the information.
Optionone() basically asks the user for information for a single contact, and every time this contact is filled out it creates a list in a list full of the diff contacts.
In optionthree() I am trying to ask a user for a contact they want to display. So once they type in the name of the contact, the code should display the entire list consisting of the contact's information (name, address, phone, email).
I've excluded the other options that are irrelevant to this problem.
contact = []
def optionone():
contactinfo = []
name = str(input("Name: "))
address = str(input("Address: "))
phone = str(input("Phone: "))
email = str(input("Email: "))
contactinfo.append(name)
contactinfo.append(address)
contactinfo.append(phone)
contactinfo.append(email)
contact.append(contactinfo)
contactinfo = []
This is the optionthree function.
def optionthree(contactinfo):
search = input("Name of contact: ")
if search in contactinfo:
print("This is what I'm trying to figure out")
else:
print("There is no contact with that name in your address book.")
return contactinfo
And the main menu function
def menu():
option = int(input("""
Menu Options:
1. Add new contact
2. Display address book
3. Search for contact
4. Modify contact
5. Delete contact
6. Exit
Choose an option: """))
if option == 1:
optionone()
elif option == 3:
info = optionthree(contactinfo)
main()
Right now, when I run this in terminal, it tells me that I'm referencing to the variable contactinfo before it is assigned. The whole concept of parameters and passing variables through functions is very confusing for me; what is wrong in this code?
you use contactinfo in the main function, but didn't define it in the main function. I notice you define a global variable "contact". Not sure if it is the same variable
It looks like you are attempting to reference contactinfo before it gets assigned any values. If you need to have executed option 1 before executing option 3, then you may want option 3 to first check if contactinfo exists. If it doesn't exist, I would suggest writing that line as the following:
info = optionthree(optionone())
Here at Stack Overflow, we handle one problem at a time. In this case, the immediate problem is the undefined variable. Please handle the info look-up in a separate posting, if you still can't figure it out.
I'm going to get rid of extra information for illustration. It's a good programming technique: take little steps. First, we're going to get a name only into the list and be able to find it. You have almost everything hooked up.
The basic principle to remember is that each function has its own "name space" (directory of variables and values). Functions communicate with each other through the parameter list and return values. Yes, there are global variables, too. For now, don't use them.
The purpose of option_one is to add a name to the info list, and make the change available to the main program. You forgot the last part: you have to send back the updated list when you're done:
def option_one(contact_list):
name = str(input("Name: "))
contact_list.append(name)
print("OPT 1 contact_list", contact_list) # trace what you do for debugging purposes.
return contact_list
def menu():
# Menu text omitted
master_list = []
if option == 1:
master_list = option_one(master_list)
print("MAIN ", master_list)
elif option == 3:
info = option_three(master_list)
menu()
Make your main program "own" the master list -- the option functions merely get a copy, do their "thing", and return the updated list (if needed). The main program has to initialize that list, master_list, and hand it off to each chosen function.
Each function has its own little world: what it got from the calling program, the local variables it creates, and what it hands back when it's done. Each routine can call that contact list by whatever local name it chooses; I've called it contact_list (as you did, but with "Pythonic" punctuation).
Output:
Choose an option: 1
Name: Mark
OPT 1 contact_list ['Mark']
MAIN ['Mark']
I'm still kind of learning Python, but my friend who has programmed in Python before says this should work fine, but it wont?
All code before this was the beginning story for this basic "escape the room" game I'm making. The code up until here works, (basic print functions describing the game).
I give the player the scenario that they're in a room and they can do one of two things:
def intro_room_input():
intro_action = input("What would you like to do? (Please enter either: 1 or 2) ")
return intro_action;
These two functions are for when they choose 1 or 2, the next if/elif function runs these functions
If they choose 1:
def intro_room_result1():
print(
"""
(Story stuff for the result of option 1. Not important to the code)
""")
return;
This function will play out if they choose 2
def intro_room_result2():
print(
"""
(Story stuff for the result of option 2. Not important to the code)
""")
return;
This will be the function for taking the player's input and continuing the story from there.
def intro_action_if(string):
if string == "1":
intro_room_result1()
elif string == "2":
intro_room_result2()
else:
print("I'm sorry, that wasn't one of the options that was available..."+'\n'+
"For this action, the options must be either '1' or '2'"+'\n'+
"Let me ask again...")
intro_room_input()
intro_action_if(string)
return;
that last intro_room_input runs fine, it re-runs the previous input, but when you actually enter 1 or 2, it doesn't do anything with them. It doesn't want to re-run the if/elif/else function to give the results.
finally I have a main that runs everything:
def main():
string = intro_room_input()
intro_action_if(string)
return;
main()
Please help, I have no idea what's wrong with this code!?
The problem is in your intro_action_if(). When you are calling the function to get values again, you forgot to change the string value.
ie,
#intro_room_input() #wrong
string = intro_room_input() #right
intro_action_if(string)
As you can see, even though in your code you asked for the user input and returned it, you forgot to reassign string with the returned value. Hence it kept the same input you had given previously and passed that old value to intro_action_if().
I'm making a text-based game and need an application-wide command line that's able to be pulled up at any text entry. My plan was to have the commands contained within a module, and execute command(), which would then allow the user to enter a command (or get a list) that is then run (contained within the same module). This didn't work because I need a way to return to where the user was. Is there anyway to return to where the user was before they entered command mode, or is there a better way to do this?
This was my idea:
import commands
def something():
print "a question"
action = raw_input("> ")
if action == "command":
commands.commands()
elif "something else" in action:
do something
else:
error.error(1)
something()
Which then went to commands.py:
def commands():
print "Enter a command, help for a list, blah blah blah."
command = raw_input("$ ")
if command == "bag":
bag()
elif command == "other":
other()
def bag():
print "Action listing things in bag"
The problem is returning where the user left off.
What you need is a main game loop:
while game.is_running:
command = get_user_input()
user_do(command)
update_world()
This will repeat the three lines of code inside the while loop for as long as game.is_running is True. First, you get the user input. Next, you act on it. Finally, you perform any other updates your game needs, like moving or spawning monsters. At this point, it loops back and asks the user for another command.
Update: here is a working example:
# In commands.py:
def bag():
print 'bag'
def other():
print 'other'
def unrecognized():
print 'unknown command'
# In main.py:
import commands
def user_input():
print 'a question'
return raw_input('>')
def user_do(command):
# get the matching command out of commands, or pass back
# the unrecognized function if it's not found
action = getattr(commands, command, commands.unrecognized)
action()
is_running = True
while is_running:
command = user_input()
if command == 'quit':
is_running = False
else:
user_do(command)
In this example, I've cheated and am relying on the user input commands being identical to the name of the functions to be called. In user_do, the getattr call compares the string the user has input with the contents of the command module, returning the function of the same name if one exists, or the fallback function unrecognized if it doesn't. action will now either hold the command function or unrecognized.
If you don't want to have your user commands so tightly bound to the actual functions themselves, you can use a dict as a branching construct (or dispatch) instead of having a lot of if / elif / else statements:
# Modified main.py
import commands
COMMAND_DISPATCH = {
'bag': commands.bag,
'sack': commands.bag,
'other': commands.other,
# ...
}
# ...
def user_do(command):
action = COMMAND_DISPATCH.get(command, commands.unrecognized)
action()
In this example, rather than look up the functions in the commands module, we look them up in COMMAND_DISPATCH instead.
One more bit of advice: pretty soon you'll want to look at parsing the user input into more than just a single command. For this example, let's assume you want to be able to accept input of the form "command ... ". You can extend the user_input function to take care of this:
def user_input():
print 'a question'
user_input = raw_input('>').split(' ')
command = user_input[0]
arguments = user_input[1:]
return command, arguments
So if you enter 'foo bar baz', this would return the tuple ('foo', ['bar', 'baz']). Next we update the main loop to deal with the arguments.
while is_running:
# use tuple unpacking to split into command, argument pairs
command, arguments = user_input()
if command == 'quit':
is_running = False
else:
user_do(command, arguments)
Then make sure we pass them to the command:
def user_do(command, arguments):
action = COMMAND_DISPATCH.get(command, commands.unrecognized)
action(arguments)
And finally, we modify the commands to accept and handle the arguments:
def bag(arguments):
for argument in arguments:
print 'bagged ', argument
For a text adventure, you'll want a more substantial parser, something that deals with command object, command object preposition subject, and possibly even command adjective object ....
You should research "python finite state machine". It is pretty much exactly what you want.
Charming Python: Using state machines
Finite-state machine
wiki.python.org/moin/FiniteStateMachine
What is a state machine?
An overly accurate description of a state machine is that it is a
directed graph, consisting of a set of nodes and a corresponding set
of transition functions. The machine "runs" by responding to a series
of events. Each event is in the domain of the transition function
belonging to the "current" node, where the function's range is a
subset of the nodes. The function returns the "next" (perhaps the
same) node. At least one of these nodes must be an end-state. When an
end-state is reached, the machine stops.
When to use a state machine ...
Start in an initial state.
Read a line of input.
Depending on the input and the current state, either transition to a new state or process the line as appropriate for the current state.
Similar to what #MatthewTrevor suggested in his answer, you would have a main loop, and pass a "state" context to the first entry point call (start or intro or whatever). That call can change the state context to point at something else. When control reaches back to the main loop again and it checks the state, it will run the new state.