I was trying to make a "game" in Python where the user inputs a command. However, I do not know whether you can take that input to be a function name. This is my current effort:
def move():
print("Test.")
if __name__ == "__main__":
input("Press enter to begin.")
currentEnvironment = getNewEnvironment(environments)
currentTimeOfDay = getTime(timeTicks, timeOfDay)
print("You are standing in the {0}. It is {1}.".format(currentEnvironment, currentTimeOfDay))
command = input("> ")
command()
Here, the input was move, as I wanted to try and call that function (as a potential end user might). However, I get the following error:
Traceback (most recent call last):
File "D:\Text Adventure.py", line 64, in <module>
command()
TypeError: 'str' object is not callable
I was wondering if there was any way that I could allow a user to 'move' in the game, which the program achieves by calling the "move" function.
It looks like you're using python3.x where input returns a string. To recover the python2.x behavior, you need eval(input()). However, you shouldn't do this. It's likely to lead to a bad day.
A better idea is to put the functions into a dictionary --
def move():
#...
def jump():
#...
function_dict = {'move':move, 'jump':jump }
and then:
func = input('>') #raw_input on python2.x
function_dict[func]()
The following code works for me on python3.2.
def move():
print("Test.")
func_dict = {'move':move}
if __name__ == "__main__":
input("Press enter to begin.")
currentEnvironment = "room" #getNewEnvironment(environments)
currentTimeOfDay = "1 A.M." #getTime(timeTicks, timeOfDay)
print("You are standing in the {0}. It is {1}.".format(currentEnvironment, currentTimeOfDay))
command = input("> ")
func_dict[command]()
You can access functions by name using:
function = globals()[function_name]
if the function is in the current module, or
function = getattr(other_module, function_name)
You should also take measures to disallow calling arbitrary functions, for example, prefixing:
def cmd_move() # ok to call this
def cmd_jump() # ok to call this
def internal_func....
cmd = raw_input('>') # e.g. "move"
fun = globals()['cmd_' + cmd]
fun()
Have a look at the cmd module. See this.
It is normally used for shell style comman dlanguages, but it can also be used to create simple text style adventure games.
You can create commands by creating a new method on the Cmd subclass.
E.g.
def do_move(self, args):
if self.next_room.has_snake():
print "The next room contains a poisonous snake. It bites you and you die."
else:
print "The room is empty"
It's usually better to re-use code as Hans suggests, but if you wanted to input commands and run them manually, it would be MUCH safer to have a dictionary of valid commands than to directly execute user-provided input.
cmd = { 'move': move, 'jump': jump, 'look': look }
Related
I have been dealing with this question for quite a time, so I decided to ask directly here for explanations/ what and where to read from.
From university we are doing a project where we use python and the cmd class to call the methods as arguments to the command line.
The lecturer has provided us with some example on how it could work and so on. However he didn't fully explained some details that I still miss about the arguments and how in general you can call the function as an argument in the command line prompt.
Here I will provide a shortened version of the code which he has written, as the general methods are the only thing included here in order to explain the situation in simpler manner.
import cmd
class Multiplayer(cmd.Cmd):
def __init__(self):
"""Init the object."""
super().__init__()
self.dice = dice.Dice() # dice object to call the roll() later
self.player1 = player.Player(1) # score = 0, index = 1
self.player2 = player.Player(2) # score = 0, index = 2
self.playerTurn = player.Player(1) # score = 0, index = 1
def do_start(self, _): #here is the part i dont fully understand
"""start a new game"""
print("You have started a new game.\n")
print("""
Welcome to the game. Type help or ? to list commands.\n
To set both players names, type: 'set_names' \n""")
self.__init__() #calling constructor so the new game starts
def do_exit(self, _):
"""Leave the game."""
print("press 'l' to leave game, press 's' to start a new one")
comand = input()
if comand == 'l':
return True
elif comand == 's':
self.do_start(self)
else:
print("unknow syntax")
self.do_exit(self)
def do_EOF(self, arg):
"""Leave the game."""
return self.do_exit(arg)
When I type "start" this function is called byt the cmd and executed. In general does the "do_" part infront of the function name has to do something with the command line itself? Why do we need this second argument (the underscore dash)? And what is it for?
(I have tried to remove it but then i typed in "-help", couldn't see the command.) I have checked other's classmates codes and they have used other words instead of underscore dash.
If you provide me with some sources/explanations so I can get a better grasp of this concept, it would be really appreciated.
Thanks in advance for the replies. Cheers!
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.
I am making a text game (various smaller text games until I am absolutely comfortable.), and there will be a lot of commands. So for example:
If the player is in the "Credits" screen. And if there is one central command, for example, "help". How would I have the command "help" list all of the available commands?
What I am asking is, how would I store all of the custom commands in a class, then call them? Or is it even possible?
The module cmd is often overlooked but sounds like just what you might be needing. As they say, the batteries are included.
Firstly, please use the search function, or at least Google. Do not expect help if you haven't demonstrated you've done your fair share of researching.
That said, here's an example to get you started. You might write a function to accept input from the keyboard and use conditional statements to output the correct information:
class MyClass():
def menu(self):
strcmd = raw_input('Enter your input:')
if strcmd == "help":
self.help_func()
elif strcmd == "exit":
sys.exit(0);
else:
print("Unknown command")
def help_func(self):
print("Type 'help' for help.")
print("Type 'exit' to quit the application.")
# ...
If you want to get fancy, you can store function pointers in a dictionary and avoid conditionals altogether:
class MyClass():
def __init__(self):
self.cmds = {"help": help_func, "info": info_func}
def menu(self):
strcmd = raw_input('Enter your input:')
if strcmd in self.cmds:
self.cmds[strcmd]() # can even add extra parameters if you wish
else:
print("Unknown command")
def help_func(self):
print("Type 'help' for help.")
print("Type 'exit' to quit the application.")
def info_func(self):
print("info_func!")
A text based menu is a no-brainer for those with a general understanding of Python. You will have to figure out how to properly implement input and control-flow on your own. This is one of the top results on Google:
http://www.cyberciti.biz/faq/python-raw_input-examples/
Probably the best first thing to remember is that functions are first-class objects in python.
So you can learn how to use a dict to map a string (help topic) to a function (which presumably somehow displays what you want).
available_commands = {"Credits": [ helpcmd1, helpcmd2, ...],
# ... other screens and their command help functions
}
if current_screen in available_commands.keys ():
for command in available_commands [current_screen]:
command ()
else:
displayNoHelpFor (current_screen)
well you could create methods in the class for each command
for example:
class Credits():
def __init(self):
print "for command 1 press 1:"
print "for command 2 press 2:"
print "for command 3 press 3:"
print "for command 4 press 4:"
choice = raw_input("")
if choice == "1":
self.command1()
elif choice == "2":
self.command2()
elif choice == "3":
self.command3()
else:
self.command4()
def command1(self):
#do stuff
def command2(self):
#do stuff
def command3(self):
#do stuff
def command4(self):
#do stuff
then each choice will do a differentnop method and each method will do a command
I dont know if this is exactly what you want bu i hope this helps
I was trying to make a "game" in Python where the user inputs a command. However, I do not know whether you can take that input to be a function name. This is my current effort:
def move():
print("Test.")
if __name__ == "__main__":
input("Press enter to begin.")
currentEnvironment = getNewEnvironment(environments)
currentTimeOfDay = getTime(timeTicks, timeOfDay)
print("You are standing in the {0}. It is {1}.".format(currentEnvironment, currentTimeOfDay))
command = input("> ")
command()
Here, the input was move, as I wanted to try and call that function (as a potential end user might). However, I get the following error:
Traceback (most recent call last):
File "D:\Text Adventure.py", line 64, in <module>
command()
TypeError: 'str' object is not callable
I was wondering if there was any way that I could allow a user to 'move' in the game, which the program achieves by calling the "move" function.
It looks like you're using python3.x where input returns a string. To recover the python2.x behavior, you need eval(input()). However, you shouldn't do this. It's likely to lead to a bad day.
A better idea is to put the functions into a dictionary --
def move():
#...
def jump():
#...
function_dict = {'move':move, 'jump':jump }
and then:
func = input('>') #raw_input on python2.x
function_dict[func]()
The following code works for me on python3.2.
def move():
print("Test.")
func_dict = {'move':move}
if __name__ == "__main__":
input("Press enter to begin.")
currentEnvironment = "room" #getNewEnvironment(environments)
currentTimeOfDay = "1 A.M." #getTime(timeTicks, timeOfDay)
print("You are standing in the {0}. It is {1}.".format(currentEnvironment, currentTimeOfDay))
command = input("> ")
func_dict[command]()
You can access functions by name using:
function = globals()[function_name]
if the function is in the current module, or
function = getattr(other_module, function_name)
You should also take measures to disallow calling arbitrary functions, for example, prefixing:
def cmd_move() # ok to call this
def cmd_jump() # ok to call this
def internal_func....
cmd = raw_input('>') # e.g. "move"
fun = globals()['cmd_' + cmd]
fun()
Have a look at the cmd module. See this.
It is normally used for shell style comman dlanguages, but it can also be used to create simple text style adventure games.
You can create commands by creating a new method on the Cmd subclass.
E.g.
def do_move(self, args):
if self.next_room.has_snake():
print "The next room contains a poisonous snake. It bites you and you die."
else:
print "The room is empty"
It's usually better to re-use code as Hans suggests, but if you wanted to input commands and run them manually, it would be MUCH safer to have a dictionary of valid commands than to directly execute user-provided input.
cmd = { 'move': move, 'jump': jump, 'look': look }
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.