How can I turn a user input into a global function? (Python) - python

I'm trying to create my own text game, as instructed in Ex 45 of Learning Python the Hard Way, but I'm a bit stuck. I have my own inventory system set up and I need to figure out how to display a list of the inventory any time the user types "inventory" (I also want to do similar things for "help")... I know that I could add an if-statement after every raw_input for it, but I wanted to see if there was some global function or code that I could use to make this a lot easier on me.
I've searched and searched but I have no idea how to phrase the question or what I could possibly do to fix this. Here's my inventory set-up, with how I'm using to call it:
class Item(object):
def __init__(self, name, quantity=1):
self.name = name
self.raw = name.strip().lower()
self.quantity = quantity
def recalc(self):
self.netValue = self.quantity * self.value
class Container(object):
def __init__(self, name):
self.name = name
self.inside = {}
def __iter__(self):
return iter(self.inside.items())
def __len__(self):
return len(self.inside)
def __contains__(self, item):
return item.raw in self.inside
def __getitem__(self, item):
return self.inside[item.raw]
def __setitem__(self, item, value):
self.inside[item.raw] = value
return self[item]
def add(self, item, quantity=1):
if quantity < 0:
print "ERROR."
if item in self:
self[item].quantity += quantity
self[item].recalc()
else:
self[item] = item
inventory = Container("Inventory")
And here's what I'm using to call it when inventory is typed:
print "Inventory: [" + ",".join((item[1].name for item in inventory)) + "]"

You could create a function for each valid user input, such as inventory
Then, you could do:
input = raw_input('...')
self.method = getattr(<your class>, input)
self.method()
which would call
def inventory(self, ...):
pass

you could use a dictionary combined with lambdas, this would be compact and fast
from __future__ import print_function
#store commands
inputLookup = {"Inventory" : lambda: print ("Inventory: [" + ",".join((item[1].name for item in inventory)) + "]"), "other text" : lambda: 3} #and so on
text = input() #replace with hover you get input
inputLookup[text]() # call the function from dictionary at that command
the import will change all your print statements to a print() however.
For lambdas you can also do.
def f():
print "Inventory: [" + ",".join((item[1].name for item in inventory)) + "]"
inputLookup = {"Inventory": lambda: f()}
text = input()
try:
inputLookup[text]
except:
print "that is not a valid input" #or something
this will allow you to use the old print statment
yes, you should never use recursion to the same function in this manner, you'll generate a large stack. Also, those print statements are in a weird place.
def func1():
print "Uh oh."
print "You're outside the house and it's quiet."
print "You EXAMINE and find a ROCK."
While True:
userinput1 = raw_input(">>> ")
if userinput1 == "inventory":
print "Inventory: [" + ",".join((item[1].name for item in inventory)) + "]"
elif userinput1 == "pick up":
if rock not in inventory: # so they can't pick up infinite rocks
inventory.add(rock)
print "You picked up a ROCK."
else:
print "you've already picked up the rock"
elif userinput1 == "examine":
print "Man's best friend."
else:
print "Let's go on about our way then."
break
I failed to see you were just starting out. I would stay away from lambda's for the moment, as they're a bit more advanced, sorry for the confusion. Before, if you look at your if/elif/else tree, there was no way for the else statement to be called, so i've edited it a bit, i hope it functions the way you intended. Also, are inventory and rock globals? if not you would need to declare or reference them in the function. (although as a future note, staying a way from globals is generally good)
hmm...i assume you mean items like the rock and such.
Items = {'rock': Rock(), 'item2': Item2(), 'item3' : item3()} #where Item() is creating the object
Inventory.add(Items[itemname]) # adds the item
You could make Items as a global so you can access it everywhere. This is ok for now, but as you learn, you should generally stay away from globals.

Related

Python printing an Else statement when not supposed to [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 months ago.
Improve this question
I'm having trouble trying to get a game creation exercise to stop printing the else statement (at the bottom of the code block). the idea is, you can navigate from room to room, but if you go in a direction you're not supposed it should tell you. However, it seems to be doing that even when you CAN go somewhere. I'd greatly appreciate any advice.
Code is below:
class Room:
number_of_rooms = 0
def __init__(self, room_name):
self.name = room_name
self.description = None
self.linked_rooms = {}
self.character = None
Room.number_of_rooms = Room.number_of_rooms + 1
def set_description(self, room_description):
self.description = room_description
def get_description(self):
return self.description
def set_name(self, room_name):
self.name = room_name
def get_name(self):
return self.name
def describe(self):
print(self.description)
def set_character(self, new_character):
self.character = new_character
def get_character(self):
return self.character
def describe(self):
print( self.description )
def link_room(self, room_to_link, direction):
self.linked_rooms[direction] = room_to_link
def get_details(self):
print(self.name)
print("--------------------")
print(self.description)
for direction in self.linked_rooms:
room = self.linked_rooms[direction]
print( "The " + room.get_name() + " is " + direction)
def move(self, direction):
if direction in self.linked_rooms:
return self.linked_rooms[direction]
else:
print("You can't go that way")
return self
I would greatly appreciate any advice on this, it's maddening. I just need it to stop printing "You can't go that way" when you can. It actually does work, it just insist on printing it every time you go into a new room as well as when you can't.
This is the code it links to
foyer = Room("foyer")
ballroom = Room("ballroom")
dining_hall = Room("dining hall")
kitchen = Room("kitchen")
foyer.link_room(ballroom, "south")
ballroom.link_room(foyer, "north")
ballroom.link_room(dining_hall, "east")
dining_hall.link_room(ballroom, "west")
dining_hall.link_room(kitchen, "north")
kitchen.link_room(dining_hall, "south")
If you add the following test code to the end of your class (assuming that it is inside a module Room.py):
if __name__ == "__main__":
print("Testing")
# rooms
room1 = Room("Floor")
room2 = Room("Kitchen")
room3 = Room("Living Room")
# link the rooms
room2.link_room(room1, "left")
room3.link_room(room1, "right")
# move
room2.move("up") # not allowed
room3.move("right") # should be possible
Then you can run the test code directly if you execute the module.
Now if you are in room 3 (living room) it is possible to get out on the right.
But if you are in room 2 (kitchen) you can only move to the left.
The test prints "You can't go that way" only if you do a move like room2.move("up") which is correct, because only "left" is allowed. Comment that line and you won't see that message any more.
According to this test, the class is behaving as it should. Note that you could (and should!) also write a unit test from the example I gave, asserting the expected output.
Update:
In your example, allowed moves are:
# allowed
kitchen.move("south")
dining_hall.move("north")
ballroom.move("east")
foyer.move("south")
And examples for not allowed moves are:
# not allowed
kitchen.move("west")
dining_hall.move("east")
ballroom.move("south")
foyer.move("north")
For these you will get "You can't go that way".
Maybe the issue you had was that you were using objects rather than strings as parameter to describe the direction.
For example, this will always fail (printing "You can't go that way"):
foyer.move(ballroom) # param should be a string, not an object
To prevent this kind of error, you could add a check to the move method:
def move(self, direction):
if not isinstance(direction, str):
raise ValueError("Direction needs to be a string!")
if direction in self.linked_rooms:
return self.linked_rooms[direction]
else:
print("You can't go that way")
return self
With that addition, the application will throw an exception, if you pass an object and not a string:
ValueError: Direction needs to be a string!
For interactive testing, you could use this code:
new_dir = "nop"
current_room = foyer
while new_dir != "":
print("current room: " + current_room.name)
print("please enter direction:")
new_dir = input()
if new_dir == "":
print("leaving")
break
new_room = current_room.move(str(new_dir))
if new_room != current_room:
print("moving to: " + new_room.name)
current_room = new_room
For debugging, it might be also helpful if you add the following code to the top of the module:
def Log(func):
def inner(*args, **kwargs):
print(f"Logging {str(func)}: {args[1:]}")
result = func(*args, **kwargs)
print(f"Result: {str(result)}")
return result
return inner
Now you can decorate any of the functions with the #Log attribute like so:
#Log
def __init__(self, room_name):
...
#Log
def move(self, direction):
...
Whenever such a decorated function is called, it will print it to the console, e.g.:
please enter direction:
south
Logging <function Room.move at 0x000001994B97C720>: ('south',)
Result: <main.Room object at 0x000001994B97A150>
moving to: ballroom
current room: ballroom
please enter direction:
If you're done with debugging, you can comment out the attributes (# #Log) to remove the extra print outs.

Can't run through a list in print function

I'm a beginner to python. I've written this code but I can't execute the for loop inside the print function to iterate through the list of marks:
class student:
def __init__(self, name, age, iden, lMark):
self.name=name
self.age=age
self.iden=iden
self.lMark=lMark
def printAve(self, obj):
for i in obj.lMark:
res+=i
av=res/len(lMark)
return av
def disInfo(self, obj):
print("the name is: ",obj.name)
print("the age is: ",obj.age)
print("the identity is: ",obj.iden)
print("the marks are: ", for i in lMark:
print(i))
def addStudent(self, n, a, i, l):
ob=student(n,a,i,l)
ls.append(ob)
return true
def searchStudent(self, _val):
for i in len(ls):
if ls[i]==_val:
return i
ls=[]
s=student("Paul", 23,14, list(15,16,17,20,12))
bool added = s.add("Van", 20, 12, list(12,18,14,16))
if added==True:
print("Student added successfully")
for i in range(ls.__len__())
s.disInfo(ls[i])
Can someone help me to solve this problem and explain me how to do?
You can't put a bare for loop in the argument list to print, and of course the embedded print doesn't return what it prints. What you can do is
print("the marks are:", ", ".join(lMark))
or perhaps
print("the marks are:", *lMark)
(Also, I believe you mean obj.lMark.)
To reiterate, if you call some code in the argument to print, that code should evaluate to the text you want print to produce; not do printing on its own. For example,
def pi()
return 3.141592653589793 # not print(3.141592653589793)
def adjective(arg):
if arg > 100:
return "big" # not print("big")
else:
return "small" # not print("small")
print(str(pi()), "is", adjective(pi()))
Notice how each function call returns something, and the caller does something with the returned value.
from statistics import mean
# classes are named LikeThis
# constants named LIKE_THIS
# other variables should be named like_this
# hungarian notation is not used in Python
class Student:
# instead of a global variable named ls,
# I'm using a class variable with a clear name instead
all_students = []
def __init__(self, name, age, iden, marks):
self.name = name
self.age = age
self.iden = iden
self.marks = marks
def printAve(self):
# you don't need to pass two arguments when you're only operating on a single object
# you don't need to reinvent the wheel, see the import statement above
return mean(self.marks)
def disInfo(self):
print("the name is:", self.name)
print("the age is:", self.age)
print("the identity is:", self.iden)
# you can't put a statement inside of an expression
# I'm guessing you want the marks all on the same line?
# the *args notation can pass any iterable as multiple arguments
print("the marks are:", *self.marks)
# this makes more sense as a classmethod
# clear variable names are important!
#classmethod
def addStudent(cls, name, age, iden, marks):
# I'm using cls instead of Student here, so you can subclass Student if you so desire
# (for example HonorStudent), and then HonorStudent.addStudent would create an HonerStudent
# instead of a plain Student object
cls.all_students.append(cls(name, age, iden, marks))
# note the capital letter!
return True
# again, this should be a classmethod
#classmethod
def searchStudent(cls, student):
# use standard methods!
try:
return cls.all_students.index(student)
except ValueError:
return None
# the literal syntax for lists in Python is `[1, 2, 3]`, _not_ `list(1, 2, 3)`.
# it also makes more sense to use Student.addStudent here, because just calling Student() doesn't add it
# to the list (although you could do that in __init__ if you always want to add them to the list)
Student.addStudent("Paul", 23, 14, [15, 16, 17, 20, 12])
# in Python, type annotations are optional, and don't look like they do in C or Java
# you also used `add` instead of `addStudent` here!
added: bool = Student.addStudent("Van", 20, 12, [12,18,14,16])
# don't need == True, that's redundant for a boolean value
if added:
print("Student added successfully")
# never call `x.__len__()` instead of `len(x)`
# (almost) never use `for i in range(len(x))` instead of `for item in x`
for student in Student.all_students:
student.disInfo()
First I answer your initial question, you can print a list in different ways, here are some of them.
You can iterate through it with a for loop and print every element on a different line:
for elem in self.lMark:
print(elem)
You can also append all values to a string and separate them by a character or something.
(Note: There will be a trailing space at the end.)
myString = ""
for elem in self.lMark:
myString = myString + str(elem) + " "
print(myString)
Better is this by doing it with strings-join method and a short version of the container iteration:
", ".join([str(i) for i in self.lMark])
There were some more issues in the code example.
Here is a running version of the script:
class Student:
def __init__(self, name, age, iden, lMark):
self.name=name
self.age=age
self.iden=iden
self.lMark=lMark
def printAve(self, obj):
for i in obj.lMark:
res+=i
av=res/len(self.lMark)
return av
def disInfo(self):
print("the name is: ",self.name)
print("the age is: ",self.age)
print("the identity is: ",self.iden)
print("the marks are: ", ", ".join([str(i) for i in self.lMark]))
class StudentList:
def __init__(self):
self.__list_of_students = []
def add(self, s):
self.__list_of_students.append(s)
return True
def get(self):
return self.__list_of_students
def search(self, name):
for s in self.__list_of_students:
if s.name == name:
return s
return None
ls = StudentList()
s=Student("Paul", 23,14, [15,16,17,20,12])
ls.add(s)
added = ls.add(Student("Van", 20, 12, [12,18,14,16]))
if added:
print("Student added successfully")
search_name1 = "Paula"
search_name2 = "Van"
if ls.search(search_name1):
print(search_name1, "is part of the list!")
else:
print("There is no", search_name1)
if ls.search(search_name2):
print(search_name2, "is part of the list!")
else:
print("There is no", search_name2)
for student in ls.get():
student.disInfo()
print("-"*10)
I would suggest to separate the list of students and the students to two different classes as shown in the code above.
You can unpack your list with the * operator:
print("the marks are: ", *lMark)
Try setting this as a function. i.e
def quantity():
for i in lMark:
print(i)
Then,
def disInfo(self, obj):
print("the name is: ",obj.name)
print("the age is: ",obj.age)
print("the identity is: ",obj.iden)
print("the marks are: ", + quantity)

How do I trigger a conditional based on if a function has executed?

I am trying to figure out a way to change a global variable from False to True if function rope is called. With my existing code, what could I add to make this possible?
Also, the global variable that exists is called inventoryRope, and it starts off as False.
Here is my code:
def rope():
print("You pick up the rope.")
command = input("Type CONTINUE to carry on.")
if command == "CONTINUE":
nextScene()
Need to use global:
inventoryRope = False
def rope():
global inventoryRope
print("You pick up the rope.")
command = input("Type CONTINUE to carry on.")
if command == "CONTINUE":
inventoryRope = True
nextScene()
Your actual goal here appears to be tracking inventory and making its state accessible from multiple functions. In that context, your approach will work, but it doesn't scale well to arbitrary numbers of inventory items.
inventory_rope = False
def pick_up(item):
if item == "rope":
inventory_rope = True
def use(item):
if (item == "rope") and inventory_rope:
print("Used rope")
Note: Because it looks like you're keeping this very simple, I'm using strings for items here. There are certainly better ways to do this.
There are many potential ways to handle inventory; one would be to simply create a list to handle whatever the player picks up.
inventory = []
def pick_up(item):
print("You picked up", item)
inventory.append(item)
def use(item):
print("Used", item)
inventory.remove(item)
You could instead inherit from the built-in list type, if you want to build in additional/different behaviors.
class Inventory(list):
def append(self, item):
print("You picked up", item)
super().append(item)
inventory = Inventory()
inventory.append("rope")
Another possibility would be making the inventory an attribute of your player object, if there are other things the player can do that would make sense to build into a class.
class Player(object):
_inventory = None
def __init__(self):
# Note: Don't use mutable objects as default arguments
self._inventory = []
def pick_up(self, item):
print("You picked up", item)
self._inventory.append(item)
player = Player()
player.pick_up("rope")

Text-based RPG: How to apply cool downs to user input

Let's say I have a spell named heal. How can I prevent a user from spamming heal every time they are damaged. I have considered applying this to individual combat functions; however, I am not sure how to implement a global rule for this? This code may clear it up:
available_spells = ['fireball', 'heal']
equipped = {'Weapon': "Staff",
'Armor': "Robes",
'Spells': ['fireball', 'heal']}
print "Your available spell(s) is(are) '%s'. " % equipped["Spells"]
inp = raw_input("Type the name of a spell you want to use.: ").lower()
lst = [x for x in available_spells if x.startswith(inp)]
if len(lst) == 0:
print "No such spell"
print ' '
elif len(lst) == 1:
spell = lst[0]
print "You picked", spell
#COMBAT FUNCTIONS HERE
else:
print "Which spell of", equipped["Spells"], "do you mean?"
If I were to make a class that defines certain actions for spells to take, how could I implement that into the code I have? For example if I have a class of spells, with functions defining damage rules, cool down times, etc., how could I reference that function in the code I already have? i.e. the player types 'heal' and I want it to reference an above class that has those values defined to check if the player recently played the spell, and what it does when played.
Am I clear enough in this question? How should I write a spell cool-down mechanic? How can I implement this mechanic into the code above?
Instead of storing all available spells as a list, you could store them as a dictionary, which allows you to also store the desired cooldown duration:
available_spells = {
# spell name: cooldown duration in seconds
'fireball': 3.0,
'heal': 5.0,
}
Each player could have another dict that keeps track of the last time they cast each spell. When the game starts, it would be empty:
cast_spells = {}
When the player attempts to cast a spell, check if the spell name is in the cast_spells dict. If it's not, then they have not yet cast it this game, so they are allowed to cast it:
if spell_name not in cast_spells:
cast_spells[spell_name] = datetime.now()
Otherwise, if the spell name is in the cast_spells dict, check if the required cooldown has elapsed:
elif cast_spells[spell_name] + datetime.timedelta(seconds=spells[spell_name]) < datetime.now():
cast_spells[spell_name] = datetime.now()
Otherwise, the cooldown is still in effect.
else:
print 'Spell not ready.'
I would probably do it using with, an exception handler, and a simple timer. That way you can just repeat the cooldown pattern, have shared cooldowns (like shown below), or even global cooldowns, etc.
Here are the classes:
import time
class CooldownException(Exception):
pass
class Cooldown(object):
def __init__(self, seconds):
self.seconds = seconds
self.expire = None
def __enter__(self):
if not self.expire or time.time() > self.expire:
self.expire = time.time() + self.seconds
else:
raise CooldownException('Cooldown not expired!')
def __exit__(self, type, value, traceback):
pass
heal_cooldown = Cooldown(5)
def heal():
try:
with heal_cooldown:
print 'You heal yourself!'
except CooldownException as e:
print e
def apply_bandage():
try:
with heal_cooldown:
print 'You bandage yourself!'
except CooldownException as e:
print e
def drink_potion():
try:
with heal_cooldown:
print 'You quaff a potion!'
except CooldownException as e:
print e
And here's how they're used:
>>> heal()
You heal yourself!
>>> time.sleep(3)
>>> drink_potion()
Cooldown not expired!
>>> time.sleep(3)
>>> apply_bandage()
You bandage yourself!
If I were to make a class that defines certain actions for spells to take, how could I implement that into the code I have?
As you guessed, your problem is very well suited to classes.
Am I clear enough in this question?
Yes.
Your program, but with classes
Here is your program modified to use two custom classes, FireballSpell and HealSpell. Each one has a .name, which is a string, and a .cast(), which is a custom behaviour. It's nearly identical to your original code, so it should be easy for you to understand:
available_spells = [FireballSpell(), HealSpell()]
equipped = {'Weapon': "Staff",
'Armor': "Robes",
'Spells': [FireballSpell(), HealSpell()]}
while True:
print "Your available spell(s) is(are) '%s'. " % [spell.name for spell in equipped["Spells"]]
inp = raw_input("Type the name of a spell you want to use.: ").lower()
lst = [spell for spell in available_spells if spell.name.startswith(inp)]
if len(lst) == 0:
print "No such spell"
print ' '
elif len(lst) == 1:
spell = lst[0]
print "You picked", spell.name
spell.cast()
else:
print "Which spell of", [spell.name for spell in equipped["Spells"]], "do you mean?"
print ""
Run it and give it a try! Here is the complete script. I'm pretty sure it does exactly what you want.
Specific spells
Each specific class has a name, cooldown time, and specific behaviour. The parent Spell class (see bottom) handles the rest.
class FireballSpell(Spell):
def __init__(self):
self.name = "fireball"
self.cooldown_seconds = 5
def spell_specific_behaviour(self):
# do whatever you like with fireball
# this is only called if the spell has cooled down
print "casting fireball"
class HealSpell(Spell):
def __init__(self):
self.name = "heal"
self.cooldown_seconds = 10
def spell_specific_behaviour(self):
# same applies here as from FireballSpell
print "casting heal"
Spell class
This is a generic Spell class - the parent of all spells. It knows the name, cooldown time, and behaviour from the specific spells (child classes above). It also has generic cooldown mechanic that's shared by the spells:
class Spell:
# spell data - filled in by specific spells
name = "default"
cooldown_seconds = 0
last_cast_time = 0
def cast(self):
# only cast the spell if it has cooled down
if self.is_cooled_down():
# call the behaviour set by the specific spell
self.spell_specific_behaviour();
# set the last cast time to the current time
self.last_cast_time = time.time()
else:
print self.name + " has not cooled down yet!"
def spell_specific_behaviour(self):
# implement in specific spell subclasses
return
def is_cooled_down(self):
current_time_seconds = time.time()
cooldown_expire_time_seconds = self.last_cast_time + self.cooldown_seconds
return current_time_seconds > cooldown_expire_time_seconds
Again, here is the whole thing in one working script. Have fun!
META: decorators, exceptions, and with blocks? Whoa, guys. OP is just now learning about classes. Let's keep it simple here.
Here is another example using decorators...
from functools import wraps
class Cooldown(object):
def __init__(self, seconds, cooldown_message):
self.seconds = seconds
self.expire = None
self.cooldown_message = cooldown_message
def decorator(self, fail_message_callback):
def _wrap_decorator(foo):
def _decorator(*args, **kwargs):
if not self.expire or time.time() > self.expire:
self.expire = time.time() + self.seconds
result = foo(*args, **kwargs)
return result
else:
if fail_message_callback:
fail_message_callback(self.cooldown_message)
return None
return wraps(foo)(_decorator)
return _wrap_decorator
heal_cooldown = Cooldown(5, 'Cooldown not expired!')
def display(message):
print message
#heal_cooldown.decorator(display)
def heal():
display('You heal yourself!')
#heal_cooldown.decorator(display)
def apply_bandage():
display('You bandage yourself!')
#heal_cooldown.decorator(display)
def drink_potion():
display('You quaff a potion!')
heal()
time.sleep(3)
drink_potion()
time.sleep(3)
apply_bandage()

Adding a Random Item to a List for a Text-Based RPG

This is concatenated to the question I asked earlier today ("List" Object Not Callable, Syntax Error for Text-Based RPG). Now my dilemma resides in adding the herb to the player's herb list.
self.herb = []
is the starting herb list. The function collectPlants:
def collectPlants(self):
if self.state == 'normal':
print"%s spends an hour looking for medicinal plants." % self.name
if random.choice([0,1]):
foundHerb = random.choice(herb_dict)
print "You find some %s." % foundHerb[0]
self.herb.append(foundHerb)
print foundHerb
else: print"%s doesn't find anything useful." % self.name
with foundHerb being the random choice. How do I add this item to the list in a neat way (currently it prints the herb name, then "None") and allow for having several of the same herb?
Here's the herb class:
class herb:
def __init__(self, name, effect):
self.name = name
self.effect = effect
Sample list of herbs (warning: immaturity):
herb_dict = [
("Aloe Vera", Player().health = Player().health + 2),
("Cannabis", Player().state = 'high'),
("Ergot", Player().state = 'tripping')
]
Use a list.
self.herb = []
foundHerb = 'something'
self.herb.append(foundHerb)
self.herb.append('another thing')
self.herb.append('more stuff')
print 'You have: ' + ', '.join(self.herb)
# You have: something, another thing, more stuff
EDIT: I found the code from which you get foundHerb in one of your other questions (please post it in this question too!), which is:
foundHerb = random.choice(herb_dict)
When I look at herb_dict:
herb_dict = [
("Aloe Vera", Player().health == Player().health + 2),
("Cannabis", Player().state == 'high'),
("Ergot", Player().state == 'tripping')
]
This is wrong, use = for assignment. == is for testing equality.
You need to use a function in the second item in these tuples.
Don't add the second item into the list. Like this:
self.herb.append(foundHerb[0])
In your function, think what would happen if random.choice([0,1]) was 0. it would not run the if block, so no herb would ever be chosen. Perhaps in your function, you can return False to say that no herb was found. Then you can do this:
self.herb = []
myherb = collectPlants() # This will either contain a herb or False
if myherb: # If myherb is a plant (and it isn't False)
self.herb.append(myherb)

Categories

Resources