How to handle user input in Python? - python

I'm making a small game.
Now I need to figure out how to handle users input.
A user must be able to take or drop items.
Stating: 'TAKE item'.
The 'item' is in a list, so it can be anything.
command = input("> ")
command = command.upper()
if self.current_room.is_connected(command):
self.move(command)
elif command in ['HELP', 'LOOK', 'QUIT', 'INVENTORY']:
self.commands(command)
elif ??? TAKE 'item'
self.take(command)
else:
print("Invalid move!")
How do i have this code be transferred to the take method.
And how do i split those 2 word inputs?
def take(self, command):
if command == 'TAKE':
if 'item' not in self.current_room.inventory:
print('No such item.')
else:
self.current_room.inventory.remove_item('item')
self.player_inventory.add_item('item')
print('item', 'taken.')

Currently, your commands don't split the command arguments in to an arg list. This is one fairly simple way to achieve what you're looking for, by splitting into arguments before you begin your parse. This is part of a process called tokenizing in the realm of compilers.
command = input("> ")
command = command.upper().split()
if self.current_room.is_connected(command[0]):
self.move(command[0])
elif command[0] in ['HELP', 'LOOK', 'QUIT', 'INVENTORY']:
self.commands(command)
elif command[0] in ['TAKE', 'DROP']:
item = command[1]
if command[0] == 'TAKE':
self.take(command[1])
else:
self.drop(command[1])
else:
print("Invalid move!")
You should be able to fairly easily handle errors in the take and drop methods. Here are a few cases you may want to check:
displaying a message if you're not carrying the item ( when you drop it)
if the item doesn't exist in the room (when you take it)
if you're already carrying too much (when you take it)

Related

How do I get my code to run the if statement?

I'm a beginner in Python and I'm writing a code for a school project and ran into an early bug.
For some reason my if function won't run.
import time #imports computer time to program(buit in function)
count= 0
print(" Gymship") # center this
print("--------------------------------------") # this should go across the whole screen
print("Input a level to view the description or InputSign up to begin signing up for a card")
print("--------------------------------------------------------------------------")
print("Bronze")
time.sleep(1) # this wil pause the program for 1 second(for effect)
print("Silver")
time.sleep(1)
print("Gold")
time.sleep(1)
print("Platinum")
time.sleep(2)
print("-----------------------------------------------") # this should go across the whole screen
print("Sign up")
print(" ")
input()
if input == "Bronze":
print("Bronze")
print("--------------------------------------------")
print("You acquire a bronze card when you use two or less gym services")
print("2 Hours limit in the gym")
print("-------------------------------------")
print(input("Back to return to menu screen"))
count = count + 1
This is not correct:
input()
if input == "Bronze":
The way input() works is by returning a value. The name input refers to the function itself, so the function input will never equal the text "Bronze" unless you explicitly do something bad, like input = "Bronze" (it's bad because if you overwrite input, you'll no longer be able to access that function).
Instead, you should be using the returned value:
usr_input = input()
if usr_input == "Bronze":
Also, the line print(input("Back to return to menu screen")) is unnecessarily complicated; the print() will print whatever was returned by input(), but input() will display the "Back to return to menu screen" prompt without wrapping it in an if statement. So, input("Back to return to menu screen") is all you need. If you keep it the way you have it, if someone typed some text and then hit enter, the text would display again, because the print() is printing whatever that text was that the user typed.
You first need to assign a variable to the input and then check if the variable is equal to "Bronze"
Right now you are taking the input, but are not storing it anywhere. So the fixed code would be
user_input = input()
if user_input == "Bronze":

I have nested functions in a submenu that are not working as I want it to

I have a menu for booking reservations and it writes a reservation list and seating chart to text files every time someone enters a new reservation.
I have a menu that has the option to display the seating chart, purchase a seat, a nested admin menu, or quit. the admin command opens a new menu that lets you clear the contents of the reservation list, return to the main menu, or quit; or at least it is supposed to. I must have something wrong with the error checking, or maybe I cannot build it this way. Can someone see where i am going wrong? I have a large program and can post more, but would rather just post the portions i am having trouble with. the other functions are defined at the main program level(same level as the menu function), should the nested functions also be defined at that level? thanks.
def menu():
print(
'Select chioce from menu:\n\nP to purchase an available bus seat\nD to display current bus seat chart\nEnter password (admin) for admin menu\nQ to quit')
while True:
try:
menu_choice = str(input(' \n')).upper()
if menu_choice == str('D'):
display()
break
elif menu_choice == str('P'):
book()
break
elif menu_choice == str('ADMIN'):
def clear_booking(): # the nested functions are not working-
print('Clearing bookings')
with open("bookings.txt") as f:
f.write("")
def previous():
menu()
print('CB to clear bookings\nR to return to main menu\nQ to quit')
admin_choice = str(input(' \n')).upper
if admin_choice == str('CB'):
clear_booking()
elif admin_choice == str('R'):
previous()
elif admin_choice == str('Q'):
exit()
else:
print('Invalid choice')
exit()
elif menu_choice == str('Q'):
print('exiting program')
exit()
else:
print('Value not recognized.')
exit()
except ValueError:
print('Invalid entry')
return # how do i get rid of the none from this returning correctly?
print(menu())
You forgot the () at the admin_choice = str(input(' \n')).upper at the upper() function call.
Also maybe you can return a string with text instead of just return at the last line of your menu() function body
Also try to include your problem statement in the introductory text of your question to make it clear what the problem is with your code, and what you want to achieve.

Is there a way to include either a user input prompt or a time.sleep() function within a key value pair of a dictionary?

I am working on a Python text RPG, and I'm using dictionaries to give initial information to the player about the area they're visiting. (see code for example). When the player types 'look' or 'examine,' I want the console to print out what I have in the value of the EXAMINATION key. What I'd like to have it do is print a section of text at a time, and either wait for the player to hit enter before continuing or at least wait a couple of seconds before printing the next block. Is there a way to achieve this? Perhaps I'm coming at this from the wrong direction?
import time
import sys
def prompt():
print("\n" + "=========================")
print("What would you like to do?")
player_action = input("> ")
acceptable_actions = ['move', 'go', 'travel', 'walk', 'quit', 'examine', 'inspect', 'interact', 'look']
while player_action.lower() not in acceptable_actions:
print("Unknown action, try again.\n")
player_action = input("> ")
if player_action.lower() == 'quit':
sys.exit()
elif player_action.lower() in ['move', 'go', 'travel', 'walk']:
player_move(player_action.lower())
elif player_action.lower() in ['examine', 'inspect', 'interact', 'look']:
player_examine(player_action.lower())
def player_examine(player_action):
if zonemap[myPlayer.location][SOLVED]:
print("There's nothing more here to examine.")
elif zonemap[myPlayer.location][EXAMINATION]:
slowprint(zonemap[myPlayer.location][EXAMINATION])
ZONENAME = ''
DESCRIPTION = 'description'
EXAMINATION = 'examine'
SOLVED = False
UP = 'up', 'north'
DOWN = 'down', 'south'
LEFT = 'left', 'west'
RIGHT = 'right', 'east'
zonemap = {
'Fields': {
ZONENAME: "Western Fields",
DESCRIPTION: "A grassy field to the west of town.",
EXAMINATION: "The grass in this field is extremely soft." + input("> ") + "The wind feels cool on your face." + time.sleep(2) + "The sun is beginning to set.",
SOLVED: False,
UP: "The Mountains",
DOWN: "The Town",
LEFT: "",
RIGHT: "The Ocean",
},
When trying to use the time.sleep() method, I get the following error:
TypeError: can only concatenate str (not "NoneType") to str
When trying to use the input("> ") function, the text simply prints on without waiting.
Your approach doesn't work because you are immediately calling the input() or time.sleep() functions as you build the dictionary. time.sleep(), for example, returns None and that's why you get your error.
You need to call those functions later on, when you retrieved the value from the dictionary and actually want to 'slow print' the description.
You can do so in loads of different ways. You could
use a sequence (such as a list or a tuple) of strings instead of a single string, and have your slowprint() function accept a sequence and pause after printing each element.
use a sequence of strings and mix in special values that slowprint() looks for to do different things, like sleeping or asking for input.
Store a function in the dictionary, that you then call. Functions are objects too, just like strings. The function would handle all the printing and pausing.
E.g. storing a tuple of strings:
EXAMINATION: (
"The grass in this field is extremely soft.",
"The wind feels cool on your face.",
"The sun is beginning to set.",
)
then have your slowprint() function handle that:
def slowprint(lines):
"""Print each line with a pause in between"""
for line in lines:
print(line)
input("> ") # or use time.sleep(2), or some other technique
The second option, to insert special values, gives you the most power to delegate all sorts of extra functionality to other code. You'd need to test for the type of object in the sequence, but this would let you insert arbitrary actions in your examination description. Like the difference between sleeping and asking for the user to hit a key:
class ExaminationAction:
def do_action(self):
# the default is to do nothing
return
class Sleep(ExaminationAction):
def __init__(self, duration):
self.duration = duration
def do_action(self):
time.sleep(self.duration)
class Prompt(ExaminationAction):
def __init__(self, prompt):
self.prompt = prompt
def do_action(self):
return input(self.prompt)
and have the slowprint() function look for these instances:
def slowprint(examine_lines):
for action_or_line in examine_lines:
if isinstance(action_or_line, ExamineAction):
# special action, execute it
action_or_line.do_action()
else:
# string, print it
print(action_or_line)
You can make any number such actions; the point is that they all subclass ExamineAction so can be distinguished from plain strings. Put them into your sequence for the EXAMINATION key:
EXAMINATION: (
"The grass in this field is extremely soft.",
Prompt("> "),
"The wind feels cool on your face.",
Sleep(2),
"The sun is beginning to set.",
)
The possibilities are endless.

Recursion with defined functions for simple text-based Python program

I'm writing my first program - it's an idiom generator, which combines individual elements from lists of random verbs, nouns, and pronouns (that I have entered) in Madlibs style and generates a humorous expression. This is a simplified version of my source code:
baseFunction = True
def mainFunction() :
import random
quest = input("Which language do you want it in? Type 'French' or 'English'. ")
if quest == "French" or "french":
verb =
#list of verbs I have manually entered
noun =
#list of nouns I have manually entered
pronoun =
#list of pronouns I have manually entered
morenouns =
#list of nouns I have manually entered
phrase = random.choice(verb) + random.choice(noun) + random.choice(pronoun) + random.choice(morenouns)
print(phrase)
print("Now, give it some meaning and use in the world!")
elif quest == "English" or "english":
verb =
#another list of verbs I have manually entered
noun =
#another list of nouns I have manually entered
pronoun =
#another list of pronouns I have manually entered
morenouns =
#another list of nouns I have manually entered
phrase = random.choice(verb) + random.choice(noun) + random.choice(pronoun) + random.choice(morenouns)
print(phrase)
print("Now, invent some meaning for it and use it in the world!")
f8 = input("Do you want to make another one? Say 'yes' if you do. ")
if f8 == "yes" or "Yes":
mainFunction()
else:
print("Thanks for playing!")
else:
print("Didn't quite catch that. Try again! (say yes!)")
mainFunction()
def malif() :
ques = input("Want to hear a funny idiom? Say 'yes' or 'no'. ")
if ques == "yes" or "Yes":
mainFunction()
elif ques == "no" or "No":
print("Wrong answer. Try again! (say yes)")
malif()
else:
print("Didn't quite catch that. Say 'yes' or 'no'.")
while baseFunction :
malif()
mainFunction()
Essentially, I am asking the user whether they want to make an idiom, offering them a choice of language, generating the expression for them, and then asking them if they want to repeat the process. When I run the script in PyCharm, it runs the two functions in order (meaning, malif() first and then mainFunction(), as I have it at the end) but it does not pay any attention to my input (ex. if I say 'no' it runs the mainFunction anyway and will always do it in French even if I say 'English').
I used some of the tips discussed in this entry (Python - How to make program go back to the top of the code instead of closing). I think the problem lies calling the functions in their own definitions (ex. calling malif() if I answer 'no' to input 'ques', which is defined in malif() ). Yet, I have followed the tips discussed in the question that I linked and it is still not working the way that I want it to. Am I doing something wrong in formatting the code (ex. in terms of indentation) or if it is not obvious what I am doing wrong, is there a way for me to loop functions back to the beginning that was not suggested in the original question?
Thanks!
First some tips when you work with strings as input. Python will make the difference between caps and non-caps letter, thus a good way to deal with strings is to lower() them first (or upper(), ...):
Example:
ques = input("Enter Yes or No: ")
ques = ques.lower()
if ques == "yes":
# do something
elif ques == "no":
# do something else
else:
# raise error
Now I feel like your code is build in a funny way. A good habit is to separate the import from the functions, from the main program. The 2 first will be imported if the module (file) is imported, while the last one will be played when the file is executed. To do so, you can use this:
# -*- coding: utf-8 -*-
"""
docstring of the module
"""
# Imports
import random
import os
# Functions
def f():
return "Hello world"
# Main program
if __name__ == '__main__':
# Calling the function, taking the inputs and so on
In the main program, it's rather useful to deal with the possibility that an exception is raised. Moreover, if you use the cmd to display your program, the cmd will close immediately when an error is raised. This syntax is quite useful:
if __name__ == '__main__':
try:
# Do stuff
except:
import sys
print (sys.exc_info()[0])
import traceback
print (traceback.format_exc())
os.system("pause") # for windows, else easy way is to have an empty input to freeze the cmd
Now your code. I would rework it this way:
# -*- coding: utf-8 -*-
"""
Docstring
"""
# Imports
import random
import os
# Functions
def build_a_phrase(language) :
if language == "french":
verb = ["vendre", "atterir", "attaquer", "jeter"]
#list of verbs I have manually entered
noun = ["arbre", "poisson", "chien"]
#list of nouns I have manually entered
pronoun = ["un", "les"]
#list of pronouns I have manually entered
morenouns = ["chat", "oiseau"]
#list of nouns I have manually entered
choices = [random.choice(verb), random.choice(noun), random.choice(pronoun), random.choice(morenouns)]
phrase = " ".join(choices) # Add a space between the words
return phrase
elif language == "english":
verb = ["...", "...", "..."]
#another list of verbs I have manually entered
noun = ["...", "...", "..."]
#another list of nouns I have manually entered
pronoun = ["...", "...", "..."]
#another list of pronouns I have manually entered
morenouns = ["...", "...", "..."]
#another list of nouns I have manually entered
choices = [random.choice(verb), random.choice(noun), random.choice(pronoun), random.choice(morenouns)]
phrase = " ".join(choices) # Add a space between the words
return phrase
if __name__ == '__main__':
try:
# Parameters
available_language = ["french", "english"]
available_answers = ["yes", "no"]
# Safety implementation of an input
quest = ""
i = 0
while quest.lower() not in available_answers:
quest = input("Want to hear a funny idiom? Say 'yes' or 'no'. ")
i += 1
if i == 2: # number of tries
break
if quest.lower() == "no":
print ("I'm sure you meant yes.")
language = ""
i = 0
while language.lower() not in available_language:
language = input("Which language do you want it in? Type 'French' or 'English'.\n")
i += 1
if i == 2: # number of tries
break
while True:
sentence = build_a_phrase(language)
print (sentence)
print ("Now, give it some meaning and use in the world!")
f8 = ""
i = 0
while f8.lower() not in available_answers:
f8 = input("Do you want to make another one? Say 'yes' if you do. ")
i += 1
if i == 2: # number of tries
break
if f8.lower() == "no":
print("Thanks for playing!")
break
except:
import sys
print (sys.exc_info()[0])
import traceback
print (traceback.format_exc())
os.system("pause")
Hope you'll get a few good tricks from this answer, and some good habits :)
Not complete yet, when the input is wrong, an Error should be raised rather than waiting for the error resulting in the wrong input (i.e. a raise statement should be placed instead of the breaks)

How to return to beginning of loop?

search_room = raw_input("Search the:")
if search_room == "classroom":
print "You quitly make your way to the classroom, which is empty besides last night's homework"
sleep(3)
print "Enter 'inspect' into the command line to inspect the homework, or enter exit, to return to the kitchen."
action = raw_input("Command:")
if action == "inspect":
print "Hmph, uncompleted. Thats strange."
print "Enter 'inspect' into the command line to inspect the homework, or enter exit, to return to the kitchen."
action = raw_input("Command:")
if action == "exit":
print "you return to the kitchen"
search_room = raw_input("Search the:")
if action == "classroom":
I'm trying to figure out how to have this loop so i one could travel back and forth between the kitchen and the classroom, but if I try to go back to the classroom after exiting, I get an error message regarding a later 'for loop'.
If I understand your question correctly, your trying to figure out how to set up a loop that will let you go from kitchen back to classroom and so on and so forth without needing to nest an infinite amount of conditionals. I suggest you have an outer while(true) loop power the sequence of steps, and add conditions to check if a move is valid (to go to to the kitchen you must currently be in the classroom and have entered exit, ect)
You need to put the code block inside its own loop with a simple boolean sentinel value (while not stop) and if stop is set to true at any point, the otherwise endless loop will stop. Also remember the importance of python indentations for distinguishing code scopes, different from languages like java where it doesn't matter where you put the code as long as it is between the { }. Also consecutive if statements will each be executed individually unless you use if..elif which is what I think you want because you are comparing the same variable in the same scope.
Also if you have more than two rooms, like something in the game Clue, you should define some sort of scoping for each room. If you are in a room, which rooms can you access from there? I did this just with a simple dictionary scopes where each room is associated with a list of rooms it can access which is verified on getting search_room. They only have access to each other right now, but you can add more to each list to increase scope to other rooms (and add more if branches)
stop = false;
scopes = {"kitchen": ["classroom"], "classroom": ["kitchen"]}
locCur = "kitchen" #starting room
locPrev = "kitchen"
while not stop:
search_room = raw_input("Search the:")
if scopes[locCur].index(search_room) > -1 : #validate the room choice
if search_room == "classroom":
locCur = "classroom" #update current scope
print "You quietly make your way to the classroom, which is empty besides last night's homework"
sleep(3)
print "Enter 'inspect' into the command line to inspect the homework, or enter exit, to return to the kitchen."
action = raw_input("Command:")
if action == "inspect":
print "Hmph, uncompleted. Thats strange."
print "Enter 'inspect' into the command line to inspect the homework, or enter exit, to return to the kitchen."
action = raw_input("Command:")
if action == "inspect":
#print/do something else
elif action == "exit":
locCur = locPrev #set scope back to what it was
print "you return to the " + locPrev
locPrev = "classroom" #store this location
continue
elif search_room == "kitchen":
#do something for this room
print "message"
continue
elif search_room == "some other room":
#do something for this room
continue
elif search_room == "stop":
stop = true

Categories