How to pull information from classes through raw input - python

I'm well into development of a text-based RPG. Right now, my store system is very long and convoluted, in that there is a lot repeated code. The idea I currently have going on is that I have a list of items available to sell, and based off raw input from the user, it will related those items to if / else statements, assuming I have the proper item and player classes made, i.e.:
store = ['sword', 'bow', 'health potion']
while True:
inp = raw_input("Type the name of the item you want to buy: ")
lst = [x for x in store if x.startswith(inp)
if len(lst) == 0:
print "No such item."
continue
elif len(lst) == 1:
item = lst[0]
break
else:
print "Which of the following items did you mean?: {0}".format(lst)
continue
if item == 'sword':
user.inventory['Weapons'].append(sword.name)
user.strength += sword.strength
user.inventory['Gold'] -= sword.cost
elif item == 'bow'
#Buy item
#Rest of items follow this if statement based off the result of item.
As you can see, I'm using the result of the 'item' variable to determine a line of if / elif / else statements for each item, and what happens if that item name is equal to the variable 'item'.
Instead, I want the player to be able to type in the item name, and then for that raw input to be translated to class names. In other words, if I typed in 'sword', I want Python to pull the information from the 'sword' object class, and apply those values to the player. For example, a weapon's damage is transferred to the player's skill. If a sword does 5 strength damage, the player's strength will be raised by 5. How can I get python to add the values of one class to another without a shit ton of if / else statements?

If you have all your game item classes names in a single place (for example, a module), you can use Python's getattr to retrieve the class itself having its string.
SO, for example, let's suppose you have a items.py file that does something like:
from weapons import Sword, Bow, Axe, MachinneGun
from medicine import HealthPotion, MaxHealthPotion, Poison, Antidote
(or just define those classes right there in the items module)
You can there proceed to do:
import items
...
inp = raw_input("Type the name of the item you want to buy: ")
...
item_class = getattr(items, inp)
user.inventory.append(item_class.__name__)
if hasattr(item_class, strength):
user.strength += item_class.strength
and so on.
You can also simply create a dictionary:
from items import Sword, Bow, HealthPotion
store = {"sword: Sword, "bow": Bow, "health potion": HealthPotion}
...
item_class = store[inp]
...
Note that the text is quoted- it is text data, and the unquoted values are the actual Python classes- which have all the attributes and such.

Thanks to jsbueno, my code now works. Here is my official fix using his dictionary method:
from objects import ironsword
class player(object):
def __init__(self, strength):
self.strength = strength
self.inventory = []
user = player(10)
store = {'iron longsword': ironsword}
while True:
inp = raw_input("Type the name of the item you want to buy: ")
lst = [x for x in store if x.startswith(inp)]
if len(lst) == 0:
print "No such item."
continue
elif len(lst) == 1:
item = lst[0]
break
else:
print "Which of the following items did you mean?: {0}".format(lst)
continue
item_class = store[item]
user.inventory.append(item_class.name)
user.strength += item_class.strength
print user.inventory
print user.strength
Typing even 'iron' into the raw input will pull the correct item. When printing user.inventory, it returns the correct item name, e.g. ['iron longsword'], and when printing the user strength variable, it prints the repsective amount.

Related

What is the error in the following program with the help of split() function?

This program is based on separating the items given by the user in sentence form and add it to a list using split() method.
total_list = []
billed_list = []
class Naveen:
question = input('what would you like to buy : ')
def shopping_cart(self,items):
items = question.split()
for item in items:
print(item)
def billed_items(self):
for item in items:
ask = input('do u really want '+ item+' ')
if ask == 'yes':
billed_list.append(item)
if ask == 'no':
pass
print(billed_list)
items = []
spacex = Naveen()
spacex.shopping_cart(items)
Without any indication of what your program should do, it's not obvious that there are any bugs. But if we assume that your program is a very basic shopping cart, it has the following problems;
The I/O should probably be handled outside the class;
The question should not be a class global;
The handling of inputs other than "yes" or "no" should be defined -- either regard everything which isn't "yes" as "no" (this is what your code currently does, but by the looks of it, by mistake), or loop until you have received either "yes" or "no" response.
The items handled in the shopping cart should be encapsulated into the instance, not global variables.
Probably try to give the class a descriptive name, rather than a random one.
So, perhaps something like this;
class ShoppingCart:
def __init__(self):
self.items = []
def shopping_cart(self, request):
self.items = request.split()
def billed_items(self):
billed = []
for item in self.items:
ask = input('Do you really want '+ item+'? ')
if ask == 'yes':
billed.append(item)
return billed
spacex = ShoppingCart()
spacex.shopping_cart(input("What would you like to buy? "))
to_pay = spacex.billed_list()
split() out of the box splits on whitespace, so you would input items in the form
carrot carrot turnip pepper
to produce the items list ['carrot', 'carrot', 'turnip', 'pepper']
Add self in front of question and you need to use seperator inside split() function.
Please check this solution code:
total_list = []
billed_list = []
class Naveen:
question = input('what would you like to buy : ')
def shopping_cart(self,items):
for item in items:
total_list.append(item)
print("Total List:", total_list)
def billed_items(self, items):
for item in items:
ask = input('do u really want '+ item+': ')
if ask == 'yes':
billed_list.append(item)
if ask == 'no':
pass
print("Billed List:", billed_list)
items = []
spacex = Naveen()
items = spacex.question.split(',')
spacex.shopping_cart(items)
spacex.billed_items(items)
Sample Input & Output:
what would you like to buy : Apple,Malta
Total List: ['Apple', 'Malta']
do u really want Apple: yes
do u really want Malta: no
Billed List: ['Apple']

What kind of unittests make sense for a chatbot in python?

I am creating a simple chatbot at the moment and now I would like to test it using the unittests package. I am new to programming and I have only recently heard about the existence of unit tests. I am thinking that for a chatbot to be tested, it would make sense to see if it gives the right output to the right user input. So if the user writes "Hi", for example, it should output "Hey what's up?" as specified in the library (I have written a bunch of libraries for it; it is not a deep-learning-kinda-bot).
This is the code of my chatbot:
# importing regular expression operations, which we need later to access the libraries
import re
import random # later we want to pick a chatbot answer to a statement by random
from Jordan_Library import dict_smalltalk, dict_caring, dict_cursing, dict_meditating, dict_corona # import libraries
# and here we imported all the topic libraries
class JordanBot:
"""
A class that represents the abilities of Jordan the chatbot.
...
Attributes
----------
name : str
user can insert name, which will later be shown in the chat.
Methods
----------
name : str
user can insert name, which will later be shown in the chat.
"""
def __init__(self, name): # this function is always called when a new object of the class is called
"""
Constructing topics for Jordan. Takes the user's name as an argument.
"""
self.name = name
def chat(self):
"""
A function that enables chatting with Jordan after picking a topic.
Take no arguments.
"""
topics = [dict_smalltalk, dict_caring, dict_cursing, dict_meditating, dict_corona]
while True:
print("Welcome. My name is Jordan. You can now choose a topic that we can talk about.")
print("Press '0' to have some good old-fashioned smalltalk.")
print("Press '1' to tell me about your deepest sorrows and your destroyed soul.")
print("Press '2' to curse with me.")
print("Press '3' to meditate with me.")
print("Press '4' to talk about Corona.")
# execute this welcome text and tell user what to press in order to pick a topic.
choice = input(">>> ")
# initialize input
if choice == '0': # determine which key to press to initiate the specific topic
print("Alrighty, let's do some chitchatting.")# initiate welcome text for specific topic
print("Don't forget that I am sensitive to punctuation.")
elif choice == '1':
print("Please tell me about your deepest sorrows and your destroyed soul.")
print("Don't forget that I am sensitive to punctuation.")
elif choice == '2':
print("Make yourself ready. let's insult each other!")
print("Don't forget that I am sensitive to punctuation.")
elif choice == '3':
print("Ok then, let's meditate.")
print("Don't forget that I am sensitive to punctuation..")
elif choice == '4':
print("Let's talk about Corona.")
print("Don't forget that I am sensitive to punctuation..")
elif choice == 'q': # if user wants to quit
break
else: # if user pressed the wrong key.
print("Try again.")
edition = topics[int(choice)]
statement = list(map(lambda x:re.compile(x[0], re.IGNORECASE), edition))
# list(map()) applies a function to all elements of a specified object, in this case the cursing library
# lambda makes sure that re.compile is applied in a certain way to all elements of the library without being case-sensitive
# re.compile makes sure that the elemets are turned into objects that can be matched later to another item in the library
answer = list(map(lambda x:x[1], edition))
# same here, but here we pick the second argument in the list x[1], which entails Jordan's answers
while True:
userInput = input(' ' + self.name + ' >>> ') # this allows for the user to type in keys
resp = "I did not understand what you said. Also, I am sensitive to punctuation." # initalize response variable
counter = 0 # initalize counter
while resp == "I did not understand what you said. Also, I am sensitive to punctuation." and counter < len(statement): # determine when to start my loop
for i in range(0, len(statement)): # loop through the indexed library
match = statement[i].match(userInput) # look if input of the user matches with one of the words in the library
if match:
word = statement[i].split(userInput)[1] # We have to take the first element of this list
resp = random.choice(answer[i]) # if there is a match, pick a random answer from x[1]
counter += 1 # make sure that the counter is now + 1 so it does not write the initialized response from the beginning but continues with the loop
# if there is no match though, then it will write the initialized answer
if userInput == 'q':
print(random.choice(answer[i]))
print("---------------------------------")
print("Do you want to choose another topic? Pick below or press 'q' to quit for realsies.")
print("---------------------------------")
break
resp = resp.format(word)
print('____________')
print(' ')
print('Jordan >>> ' + resp) # print Jordan's answer
The unittests I am trying to create are something like:
import unittest
from Jordan_Library import dict_smalltalk, dict_caring, dict_cursing, dict_meditating, dict_corona # import dictionairies
from Jordan_Class import JordanBot
class testJordan(unittest.TestCase):
"""
A class to test several units of Jordan to make sure everything is working correctly.
"""
def test_match(self):
j = JordanBot('StringName')
j.chat()
user_input = "What are you?"
bot_output = list(map(lambda x:x[1], dict_smalltalk)) # this is how I access the right response in the right library
matched = bot_output.match(user_input)
self.assertIn("I am a chatbot, dude. What do you think?", matched)
def test_regex(self):
j = JordanBot('StringName')
j.chat()
text = 'something'
regex = {}
self.assertRegexpMatches(text, regex)
if __name__ == '__main__':
unittest.main()
The main problem is that these lines only run my code, but not really any unit tests. Advice is much appreciated!

Generating Random Combinations of Dictionary Key and Value Sets

I am creating a program to sort through a music library file. I have this one particular function, generateRandomPlaylist(musicLibDictionary), that I am stuck on.
The function needs to randomly pick a key from the dictionary and randomly assign one of the values to the key. For instance the artists in the dictionary include The Who, Adele and The Beatles. The respective albums include Tommy; 19, 21, 25; Abbey Road, Let It Be. I need the program to randomly pick one of the keys (the artists) and then randomly pick one of the key's values. The randomly generated playlist needs to have all three artists, not repeats, but different albums from the artist. The way I have it set up, the output doesn't necessarily use all three artists. Sample output should look like:
Here is your random playlist:
- 25 by Adele
- Abbey Road by The Beatles
- Tommy by The Who
Each time the function is called, the playlist should be different. Like I said, right now the function doesn't run properly, and I also get a printing error saying I cannot concatenate a list and a string, so I don't know where I am going wrong.
The code for the program is below:
# importing pickle
import pickle
import random
# declaration of functions
def displayMenu():
print("Welcome to Your Music Library")
print("Options:")
print("\t1) Display Library")
print("\t2) Display all artists")
print("\t3) Add an album")
print("\t4) Delete an album")
print("\t5) Delete an artist")
print("\t6) Search Library")
print("\t7) Generate a random playlist")
print("\t8) Make your own playlist")
print("\t9) Exit")
def displayLibrary(musicLibDictionary):
for key in musicLibDictionary:
print("Artist: " + key)
print("Albums: ")
for album in musicLibDictionary[key]:
print("\t- " + album)
def displayArtists(musicLibDictionary):
print("Displaying all artists:")
for key in musicLibDictionary:
print(" - " + key)
def addAlbum(musicLibDictionary):
artistName = input("Please enter the name of the artist you would like to add: ")
albumName = input("Please enter the name of the album you would like to add: ")
if artistName in musicLibDictionary.keys():
musicLibDictionary[artistName].append(albumName)
else:
musicLibDictionary[artistName] = [albumName]
def deleteAlbum(musicLibDictionary):
artist = input("Enter artist: ")
albumToBeDeleted = input("Enter album: ")
if artist in musicLibDictionary.keys():
if albumToBeDeleted in musicLibDictionary[artist]:
musicLibDictionary[artist].remove(albumToBeDeleted)
return True
else:
return False
else:
return False
def deleteArtist(musicLibDct):
artistToBeDeleted = input("Enter artist to delete: ")
if artistToBeDeleted in musicLibDct.keys():
del musicLibDct[artistToBeDeleted]
return True
else:
return False
def searchLibrary(musicLibDictionary):
searchTerm = input("Please enter a search term: ")
searchTerm = searchTerm.lower()
print("Artists containing" + searchTerm)
for key in musicLibDictionary.keys():
if searchTerm.lower() in key.lower():
print("\t - ", end="")
print(key)
print("Albums containing" + searchTerm)
for album in musicLibDictionary[key]:
print("\t- " + album)
for key in musicLibDictionary.keys():
for album in musicLibDictionary[key]:
if searchTerm in album.lower():
print("\t - ", end="")
print(album)
def generateRandomPlaylist(musicLibDictionary):
print("Here is your random playlist:")
for artist in musicLibDictionary.keys():
artistSelection = random.choice(list(musicLibDictionary.keys()))
albumSelection = random.choice(list(musicLibDictionary.values()))
print("\t-" + albumSelection + "by" + artistSelection)
def loadLibrary(libraryFileName):
fileIn = open(libraryFileName, "rb")
val = pickle.load(fileIn)
val = dict(val)
return val
def saveLibrary(libraryFileName, musicLibDictionary):
fileIn = open(libraryFileName, "wb")
pickle.dump(musicLibDictionary, fileIn)
def main():
musicLib = loadLibrary("musicLibrary.dat")
userChoice = ""
while (userChoice != 7):
displayMenu()
userChoice = int(input("> "))
if userChoice == 1:
displayLibrary(musicLib)
elif userChoice == 2:
displayArtists(musicLib)
elif userChoice == 3:
addAlbum(musicLib)
elif userChoice == 4:
deleteAlbum(musicLib)
elif userChoice == 5:
deleteArtist(musicLib)
elif userChoice == 6:
searchLibrary(musicLib)
elif userChoice == 7:
generateRandomPlaylist(musicLib)
elif userChoice == 8:
saveLibrary("musicLibrary.dat", musicLib)
# Call main
main()
Here's one way to do it, if I understand correctly that you want each artist exactly once in a random order and a random album from each artist:
def generateRandomPlaylist(musicLibDictionary):
print("Here is your random playlist:")
artists = list(musicLibDictionary.keys())
random.shuffle(artists) # Perform an in-place shuffle
for artistSelection in artists:
albumSelection = random.choice(list(musicLibDictionary[artistSelection]))
print("\t-" + albumSelection + "by" + artistSelection)
We know we want all the artists exactly once, but in a random order. Since the keys of the dictionary are the artists, then we can just perform a random.shuffle on the keys to get a random ordering of the artists. Then we have to look into each artist's albums (musicLibDictionary[artist]) and make a random.choice to pick out one album at random.
What your code is doing, on a line by line basis, is the following:
def generateRandomPlaylist(musicLibDictionary):
print("Here is your random playlist:")
for artist in musicLibDictionary.keys(): # For each artist
artistSelection = random.choice(list(musicLibDictionary.keys())) # Choose one artist randomly (not necessarily the one in your for loop)
albumSelection = random.choice(list(musicLibDictionary.values())) # Choose a random album list (musicLibDictionary.values() returns a list of lists, so you're just choosing a random discography (list) from a random artist)
print("\t-" + albumSelection + "by" + artistSelection) # Because this is not indented into your loop, you're likely only getting the last one chosen
The reason you were getting issues appending a string and a list (not allowed in python directly, you must cast the list to a string first) is that your albumSelection variable was a full list of the albums from a random artist, not necessarily even the artist in the artistSelection variable. Your musicLibDictionary.values() was returning something like [['Tommy'], ['19', '21', '25'], ['Abbey Road', 'Let It Be']]. random.choice picks a random value out of the list provided to it so given a list like [[1,2,3], [4,5,6]] it could pick out [1,2,3].

Python List in List ("Stuck")

def lists(): #Where list is stored
List = ["Movie_Name",[""],"Movie_Stars",[""],"Movie_Budget",[""]]
print ("Your Movies")
amount_in_list = int(input("How many Movies? "))
x = 1
while x <= amount_in_list:
film = input ("Name of film ... ")
stars = input ("Main stars ...")
Budget = input ("Budget ...")
List.append["Movie_Name"](film)
List.append["Movie_Stars"](stars)
List.append["Movie_Budget"](Budget)
lists()
How do i add the film you enter to the list under the subsetting Movie_Name etc?
A better answer than one which answers your question directly would be: You don't. You definitely need a dictionary for this situation (unless your program develops to a point where you'd prefer creating a custom object)
As a simple demonstration:
def getMovies():
movieinfo = {"Movie_Name": [], "Movie_Stars": [], "Movie_Budget": []}
print ("Your Movies")
amount_in_list = int(input("How many Movies? "))
x = 1
while x <= amount_in_list:
film = input ("Name of film ... ")
stars = input ("Main stars ...")
budget = input ("Budget ...")
movieinfo["Movie_Name"].append(film)
movieinfo["Movie_Stars"].append(stars)
movieinfo["Movie_Budget"].append(budget)
x+=1
return movieInfo
Notice that with a dict you simply use the key string to get the corresponding list (initialized at the start of the function) and append the data as desired.
Edited to provide further information for OP's updated request.
If you want to find a movie's info based on just the movie's name given by the user, you could try something like this:
film = 'The Matrix' # Assuming this is the user's input.
Try:
# The index method will throw an exception if
# the movie cannot be found. If that happens,
# the 'except' clause will execute and print
# the relevant statement.
mIdx = movieinfo['Movie_Name'].index(film)
print '{0} stars {1} and had a reported budget of {2}'.format(
film, movieInfo['Movie_Stars'][mIdx], movieInfo['Movie_Budget'][mIdx])
except ValueError:
print '{0} is not in the movie archives. Try another?'.format(film)
Output:
'The Matrix stars Keanu Reeves and had a reported budget of $80 million'
Or:
'The Matrix is not in the movie archives. Try another?'
I would store the movie information in an object. This way your code will be easier to extend, make changes and reuse. you could easily add methods to your movie class to do custom stuff or add more properties without having to change your code to much.
class Movie:
def __init__(self, name='', actors=[], rating=0 budget=0):
self.name=name
self.actors=actors
self.budget=budget
self.rating=rating
def setName(self, newname):
self.name=newname
def setActors(self, newstars):
self.actors=newstars
def setBudget(self, newbudget):
self.budget=newbudget
def setRating(self, newrating):
self.rating=newrating
# example
mymovies=[]
movie1= Movie('Interstellar',['actor1','actor2','actor3'], 5, 100000)
movie2=Movie()
movie2.setName('other movie')
movie2.setActors(['actor1','actor2','actor3'])
movie2.setBudget(10000)
mymovies.append(movie1)
mymovies.append(movie2)
# or append to your list in a loop

Python Nested If

hey im making a simple little grocery list on Python. I know it's not the most eloquent... but I am just learning the syntax right now. I want to get into learning Django.
list = []
def makeList():
listing = True
while listing:
addTo = raw_input("Add to list: ")
if addTo == 'q':
listing = False
else:
list.append(addTo)
def checkList():
if check in list:
print "Yay there is " + check + " here"
else:
print "No you have not added that..."
addAnother = raw_input("Would you like to add it? ")
if str.lower(addAnother) == "yes":
list.append(check)
elif str.lower(addAnother) == "no":
print "Okay then here is your list."
print list
else:
print check
makeList()
check = raw_input("What item: ")
checkList()
I know its pretty complex and hard to understand O_o... but you can see that the nested if statement is not registering when you run it.
What is making it do this? I think that's the best way to ask this.
I've rewritten it a bit to make it cleaner and more Pythonic;
def get_list(prompt, halt):
lst = []
while True:
item = raw_input(prompt)
if item == halt:
return lst
else:
lst.append(item)
def check_list(lst, item):
if item in lst:
print('Yay there is {} here'.format(item))
return True
else:
print('No you have not added {}'.format(item))
return False
def get_yesno(prompt):
while True:
yesno = raw_input(prompt).lower()
if yesno in {'y', 'yes'}:
return True
elif yesno in {'n', 'no'}:
return False
def main():
mylist = get_list('Add to list:', 'q')
check = raw_input('Look for item:')
if not check_list(mylist, check):
if get_yesno('Would you like to add it?'):
mylist.append(check)
print(mylist)
if __name__=="__main__":
main()
Some style tips:
Don't use list as a variable name; it's a built-in function, and you don't want to overwrite it.
Global variables are almost always a bad idea; passing data around explicitly makes it much easier to figure out where bad data is coming from, and makes functions more reusable.
camelCase is generally denigrated; use_underscores for function names instead.
You probably intended to keep going rather than break when you append the new item (or at least print something to indicate success), but the nested if statement works just fine, appends the thing to the list as specified and then the function and program terminate.

Categories