passing self to another classes function in self's function - python

I have two classes, the first one has a function move(creature, board). Then in the creature class there is a function that calls move, so how do I pass the current creature to the move function while in the creature class? Should it just be move(self, self.board), because when I try that I get a "Undefined variable from import:
move" error?
Here's the relevant code:
Creature:
class creature:
def __init__(self, social, intelligence, sensory, speed, bravery, strenght, size):
self.traits = [social, intelligence, sensory, speed, bravery, strenght]
self.x = 0
self.y = 0
self.hunger = 10
self.energy = 30
self.shelter = 0
self.dominance = 0
self.boardSize = size - 1
self.SOCIAL = 0
self.INTELLIGENCE = 1
self.SENSORY = 2
self.SPEED = 3
self.BRAVERY = 4
self.STRENGTH = 5
...
def performAction(self, action, location):
...
if action == "storeFood":
food = location.vegetation
location.vegetation = -1
simulation.move(self, self.shelter)
self.shelter.foodStorage += food
...
Simulation:
class simulation():
def __init__(self, x):
self.creatures = {creature.creature():"", creature.creature():"", }
self.map = land.landMass
self.lifeCycles = x
self.runStay = ["rfl", "rbf", "rbl", "rbf", ]
self.befriend = ["bbl", "bbf"]
self.fight = ["fbl", "fbf", "bfl", "bff", "ffl", "fff"]
...
def move(self, creature, target):
map[creature.x][creature.y].creatures.remove(creature)
creature.energy -= abs(map[creature.x][creature.y].elevation - target.elevation) / creature.getSpeed()
target.creatures.append(creature)
creature.x, creature.y = target.location
...
EDIT:
OK so I have somewhat solved the problem. Python requires that I have simulation.simulation.map(self, self.shelter) I'm assuming this means that it requires not just the class file but also an instance of that class. So the new question is do I have to make that instance somewhere else then pass it in? Or will this work with an instance of Simulation somewhere else?

Inherit the simulation class into the creature class:
class Creature(Simulation): # I have inherited the functions from Simulation into Creature
...
Now instead of simulation.move(self, self.shelter), you want:
self.move(yourparameters)
If you noticed, I capitalised your class names. It's good to do so.
For more on inheritance in classes, take a look [at the docs].(http://docs.python.org/2/tutorial/classes.html#inheritance)

Related

How to call object initialized to a number?

If I were to have these functions in a class, how would I call them from another function in the same class?
class Dead:
def initial(self):
self.amy = 1
self.bob = 2
self.cam = 3
def __init__(self):
self.initial()
def get_number(self, number):
How could I call self.amy, and in return be getting the number 1? In get_number I would like to add like self.amy to a number to return the sum, but like with all amy, bob, cam in one go with a for function maybe? I'm not sure how to word this question without completely spoiling the question, sorry.
You could change your get_number method to accept a member variable name instead and dynamically retrieve it. E.g.
class Dead:
def initial(self):
self.amy = 1
self.bob = 2
self.cam = 3
def __init__(self):
self.initial()
def get_number(self, name, number):
return getattr(self, name) + number
However, this is more than redundant. You can already access those variables from your object, adding a method to access them is adding an extra layer for no reason.
class Dead:
def initial(self):
self.amy = 1
self.bob = 2
self.cam = 3
def __init__(self):
self.initial()
dead = Dead()
dead.amy # 1
dead.bob # 2
dead.cam # 3
dead.amy += 1 # 2
So is adding an initial method to initialize your member variables. No reason not to do so inside your __init__ directly.
class Dead:
def __init__(self):
self.amy = 1
self.bob = 2
self.cam = 3
Adding useless methods is not making your code better, it really just pollute it.

Text-Based Pokemon Game: How do I implement an evolution system?

I have starting working on this Text-Based Pokemon game and I am stuck on trying to figure an evolution system that can change one class object into another class object, if that makes sense.
I've attempted to do this just by simply making the class object equal to the one I want to change:
# Trainer
new_trainer = Trainer('Trainer', 'Male')
# Test pokemon (the parameter is just a level value)
bulbasaur = Bulbasaur(10)
ivysaur = Ivysaur(20)
# Adding pokemon to party
new_trainer.add_pokemon(bulbasaur)
new_trainer.add_pokemon(ivysaur)
# Display pokemon lists
print(new_trainer.pokemon_list)
new_trainer.display_party()
# Attempting to 'evolve' bulbasuar
bulbasaur = Ivysaur(bulbasaur.lvl)
# Displaying results again to see if it worked
print(new_trainer.pokemon_list)
new_trainer.display_party()
But by looking at the output, it shows that nothing has happened:
Bulbasaur was added to your party!
Ivysaur was added to your party!
[<__main__.Bulbasaur object at 0x0000023587EDA080>, <__main__.Ivysaur object at 0x0000023587EDA0F0>]
1. Bulbasaur
2. Ivysaur
[<__main__.Bulbasaur object at 0x0000023587EDA080>, <__main__.Ivysaur object at 0x0000023587EDA0F0>]
1. Bulbasaur
2. Ivysaur
EDIT:
It turns that that the variable value DOES indeed change, but I simply need to update the Trainer's pokemon list. However, I am still unsure on how to do this.
The display_party function in the Trainer class looks like this:
def display_party(self): # Displays pokemon party list
if not self.pokemon_list:
return print("There are no pokemon in your party.")
else:
for pokemon in range(len(self.pokemon_list)):
print("{0}. {1}".format(pokemon + 1, self.pokemon_list[pokemon].name))
I was just thinking of adding an update_party function, which goes into the list, deletes the old value and inserts the new value, but how will it know what value to delete?
Perhaps there is a better way to do this? And sorry if my question doesn't include that much information, I will add more of my code if it doesn't make much sense already. This is my first time asking a question here :D
EDIT 2:
For those who don't understand how the code works, this is basically how it works so far:
# Formula used to calculate pokemon health
def health_stat_calculation(base_stat, lvl):
return int(((base_stat * 3 * lvl) / 100) + lvl + 10)
# Formula used to calculate pokemon stats
def stat_calculation(base_stat, lvl):
return int(((base_stat * 3 * lvl) / 100) + 5)
# Trainer class
class Trainer:
def __init__(self, name, gender):
self.name = name
self.gender = gender
self.pokemon_list = []
self.item_list = []
def add_badge(self, badge): # Gives player a badge
self.player_badges.append(badge)
def add_pokemon(self, pokemon): # Adds a pokemon to party
for poke in self.pokemon_list:
if pokemon is poke:
return print("You already have this pokemon in your party!")
if len(self.pokemon_list) > 5:
return print("You have too much pokemon in your party!")
else:
self.pokemon_list.append(pokemon)
return print("{} was added to your party!".format(pokemon.name))
def display_party(self): # Displays pokemon party list
if not self.pokemon_list:
return print("There are no pokemon in your party.")
else:
for pokemon in range(len(self.pokemon_list)):
print("{0}. {1}".format(pokemon + 1, self.pokemon_list[pokemon].name))
def add_item(self, item): # Adds an item to player's inventory
if len(self.item_list) > 50:
print("You have too much items in your inventory!")
else:
self.item_list.append(item)
print("{} was added to your inventory!")
# Generic pokemon class
class Pokemon:
def __init__(self, name, lvl, exp, id_number, health, attack, defence, sp_attack, sp_defense, speed):
self.name = name
self.lvl = lvl
self.exp = exp
self.id_number = id_number
self.health = health
self.attack = attack
self.defence = defence
self.sp_attack = sp_attack
self.sp_defense = sp_defense
self.speed = speed
def get_pokemon_name(self):
return self.name
# User friendly stat display
def display_stats(self):
print("\nStats for {}\n---------------".format(self.name))
print("Level: {}".format(self.lvl))
print("Index No.{}".format(self.id_number))
print("Health: {}".format(self.health))
print("Attack: {}".format(self.attack))
print("Defense: {}".format(self.defense))
print("Sp. Attack: {}".format(self.sp_attack))
print("Sp. Defense: {}".format(self.sp_defense))
print("Speed: {}\n".format(self.speed))
# Level up pokemon and show change in stats
def level_up(self):
self.display_stats()
self.lvl += 1
print("\n{} has leveled up!\n".format(self.name))
self.calculate_stats()
self.display_stats()
# Calculate generic pokemon stats
def calculate_stats(self):
self.health = health_stat_calculation(self.base_health, self.lvl)
self.attack = stat_calculation(self.base_attack, self.lvl)
self.defense = stat_calculation(self.base_defense, self.lvl)
self.sp_attack = stat_calculation(self.base_sp_attack, self.lvl)
self.sp_defense = stat_calculation(self.base_sp_defense, self.lvl)
self.speed = stat_calculation(self.base_speed, self.lvl)
# Bulbasaur class
class Bulbasaur(Pokemon):
def __init__(self, lvl, name="Bulbasaur"):
self.name = name
self.lvl = 16
self.exp = 0
self.id_number = 1
# Bulbasaur Base stats
self.base_health = 45
self.base_attack = 49
self.base_defense = 49
self.base_sp_attack = 65
self.base_sp_defense = 65
self.base_speed = 45
self.calculate_stats()
# Ivysaur class
class Ivysaur(Pokemon):
def __init__(self, lvl, name="Ivysaur"):
self.name = name
self.lvl = 16
self.exp = 0
self.id_number = 2
# Bulbasaur Base stats
self.base_health = 60
self.base_attack = 62
self.base_defense = 63
self.base_sp_attack = 80
self.base_sp_defense = 80
self.base_speed = 60
self.calculate_stats()
Casting from one class to another makes no sense in your case.
Just go with
class Pokemon():
def __init__(self, name, level=0):
self.level = level
self.name = name
def evolve(self):
self.level += 1
def __str__(self):
return 'Pokemon: {}, Level: {}'.format(self.name, self.level)
p1 = Pokemon('Bulbasaur')
p2 = Pokemon('Ivysaur')
print(p1)
print(p2)
p1.evolve()
p2.evolve()
print(p1)
print(p2)
You could turn the kind, Bulbasaur, Ivysaur, etc., into a component of the Pokemon class. The Bulbasaur has its next evolution stage as an attribute and in the evolve method of the Pokemon you can just set the kind to the next evolution stage.
class Pokemon:
def __init__(self, kind, level):
self.level = level
self.kind = kind # The kind is just a component now.
def evolve(self):
# Create a new instance of the next evolution stage
# and use it to replace the previous kind.
self.kind = self.kind.evolution_stage()
class Bulbasaur:
def __init__(self):
self.base_health = 45
# A reference to the next evolution stage class.
self.evolution_stage = Ivysaur
class Ivysaur:
def __init__(self):
self.base_health = 60
# self.evolution_stage = Venusaur
# Pass a Bulbasaur instance as the `kind` argument.
pokemons = [Pokemon(Bulbasaur(), 3)]
print(pokemons[0].kind, pokemons[0].kind.base_health)
pokemons[0].evolve() # Changes the .kind attribute.
print(pokemons[0].kind, pokemons[0].kind.base_health)
I don't know if this is the cleanest way, but somehow it worked when I added this function into the Pokemon class and used the dict dunder to update the contents of the old object to the new one. The temp_pos was used as a temporary placeholder for the current object's name so it didn't get changed when updating it to the new_pokemon object.
# Evolve function
def evolve(self, evln, trainer):
temp_name = self.name
new_pokemon = evln(self.lvl)
self.__dict__.update(new_pokemon.__dict__)
self.name = temp_name

Where did it go wrong in my code?

class Player:
def __init__(self):
self.speed
self.hp
def Berserker(self):
self.speed == 12
self.hp == 6
print("Berserkers stats are: " + Berserker())
So, What have I done wrong? As you can see, I'm very new to Python.
The error I'm getting is: TypeError: Berserker() missing 1 required positional argument: 'self'
You're missing quite a few things, but I'll help you out!
Your __init__ function doesn't do anything. Let's give it some base stats. I'll say that a Player's default speed and health will be 10 and 100, respectively. Then we'll make Berserker a subclass of Player (I think that's what you were going for?). And lastly, I'll give Player a method that will allow you to get a string-formatted output for its values.
First, the new Player:
class Player:
def __init__(self, speed=10, health=100):
self.speed = speed
self.health = health
def __str__(self):
return "A player with speed {} and health {}.".format(self.speed, self.health)
And now for the Berserker. I'll give it a base speed of 15 and health of 85. (Obviously the specifics are up to you!)
class Berserker(Player):
def __init__(self):
super().__init__(speed=15, health=85)
Lastly, we can create these and print the value. I'll make a couple different versions so you can see how it works. (And I'll use the regular Python interpreter for this).
>>> p1 = Player()
>>> p2 = Player(7, 120)
>>> b = Berserker()
>>> print(p1)
A player with speed 10 and health 100.
>>> print(p2)
A player with speed 7 and health 120.
>>> print(b)
A player with speed 15 and health 85.
Hopefully this gives you a good place to start!
You did a bunch of mistakes there :
Indent your Berserker method to be part of the class
Assignement in python is with one "=" not with "==" ( like most programming languages actually )
Give speed and hp initial values or don't put them in the constructor at all , in python variables are created when they're assigned a value.
Make your Berserker method return a string to be able to print it
Create an instance of your class
a working version of you code should be like this :
class Player:
def __init__(self):
self.speed = 0
self.hp = 0
def Berserker(self):
self.speed = 12
self.hp = 6
return "speed {} hp {}".format(self.speed,self.hp)
m = Player()
print("Berserkers stats are: " + m.Berserker())
Now that's a working version but it's still poorly designed IMO ,this is better :
class Player:
def __init__(self):
self.speed = 0
self.hp = 0
def Berserker(self):
self.speed = 12
self.hp = 6
def __str__(self):
return "speed {} hp {}".format(self.speed,self.hp)
m = Player()
m.Berserker()
print(m)

python: setting attributes from module to module

Im teaching myself python and I've come upon a snag in a simple game project I'm working on.
I would like to keep the players stats in a different module from the rooms that are being run by the game engine. Problem is when I try to set a Playerattribute from a different module, it doesn't save the new attribute and instantiates the original attribute.
here is the Playerclass in the entities module
class Player(object):
def __init__(self):
self.name = ' '
self.hp = 0
self.current_hp = 0
self.strength = 0
self.dexterity = 0
self.constitution = 0
And here is how im trying to manipulate and test the attributes in the rooms module
class CharacterCreation(Scene):
def enter(self):
character = entities.Player()
character.hp = 10
print character.hp
return 'barracks'
class Barracks(Scene):
def enter(self):
character = entities.Player()
print character.hp
return 'shop'
When I test this with the rest of my code, here is what I get.
-------------------------------------------------------------------------------
10
-------------------------------------------------------------------------------
0
-------------------------------------------------------------------------------
So what am I missing here? I thought I could set that attribute using =but it seems I'm mistaken? the first time I did it, it worked, but then how do i get python to set the new value of hp to 10?
You're creating a new Player object in each scene, changing its attributes, and then throwing it away.
You should be explicitly passing one single player into each scene:
def enter(self, player):
... do something with player ...
It looks like you're creating a new Player instance on every enter method...
If you're going to have only one player in the game, you could have it as a global variable (usually not very good idea) or even better, as a singleton class:
http://blog.amir.rachum.com/post/21850841339/implementing-the-singleton-pattern-in-python
I made some tweakings to the code. It adds the PlayerPool class (which is more like a cache, actually). It may give you some ideas :)
#!/usr/bin/env python
#http://stackoverflow.com/questions/14629710/python-setting-attributes-from-module-to-module/14629838#14629838
class Player(object):
def __init__(self):
self.name = ' '
self.hp = 0
self.current_hp = 0
self.strength = 0
self.dexterity = 0
self.constitution = 0
class PlayerPool(object):
_players = dict()
#classmethod
def getPlayerByName(cls, name):
if not name in cls._players:
newPlayer = Player()
newPlayer.name = name
cls._players[newPlayer.name] = newPlayer
return cls._players[name]
class Scene(object):
pass
class CharacterCreation(Scene):
def enter(self):
character = PlayerPool.getPlayerByName("foobar-hero")
character.hp = 10
print "%s has %s points of hp" % (character.name, character.hp)
return 'barracks'
class Barracks(Scene):
def enter(self):
character = PlayerPool.getPlayerByName("foobar-hero")
print "%s has %s points of hp" % (character.name, character.hp)
return 'shop'
if __name__ == "__main__":
step1 = CharacterCreation()
if step1.enter() == "barracks":
step2 = Barracks()
step2.enter()
That outputs:
borrajax#borrajax-comp:~/Tests/Python/Stack Overflow$ python ./players.py
foobar-hero has 10 points of hp
foobar-hero has 10 points of hp
Welcome to python. I'm sure you'll find it has really cool features... such as the ability to return functions, or pass functions as parameters, inspect the classes defined in any module... Looks like things you could find useful.

Creating a circular reference

I need to create several objects that have (often circular) references to each other. In general, several objects might be involved, but here's one simple case where I need just a pair of cars that refer to each other:
class Car:
def __init__(self, position, speed):
self.position = position
self.speed = speed
def set_reference(self, other_car):
self.other_car = other_car
# ...
def main():
# ...
car1 = Car(pos1, spd1)
car2 = Car(pos2, spd2)
car1.set_reference(car2)
car2.set_reference(car1)
A car without a reference to the other car is not a valid object. So ideally, I'd like to perform set_reference from inside the __init__ method; this would be both safer (no chance of using invalid objects) and cleaner (all initialization will be performed in __init__ as one might expect).
Is there any neat solution that achieves this goal? I don't mind creating a pair of cars at once, but each car is a standalone entity, and so it needs to be an instance in its own right.
I'm also aware that circular references are troublesome for GC; I'll deal with that.
Use case:
Each car serves as a backup for the other. Car instances are "smart", i.e., they can do a lot of work. It's annoying if the a car instance doesn't know its backup, since it prevents a car from completing actions without requiring a reference from outside every time.
I don't think there is a good way to move the set_reference() call into __init__(), because the other car might not yet exist. I would probably do something like this.
class Car:
def __init__(self, position, speed):
self.position = position
self.speed = speed
def set_reference(self, other_car):
self.other_car = other_car
#classmethod
def create_pair(cls, car1_args, car2_args):
car1 = cls(*car1_args)
car2 = cls(*car2_args)
car1.set_reference(car2)
car2.set_reference(car1)
return car1, car2
def main():
car1, car2 = Car.create_pair((pos1, spd1), (pos2, spd2))
Here is how you could expand this same concept for a larger circular reference structure:
class Car:
# ...
#classmethod
def create_loop(cls, *args):
cars = [cls(*car_args) for car_args in args]
for i, car in enumerate(cars[:-1]):
car.set_reference(cars[i+1])
cars[-1].set_reference(cars[0])
return cars
You could then call it like this (with any number of cars):
car1, car2, car3 = Car.create_loop((pos1, spd1), (pos2, spd2), (pos3, spd3))
You should up with the references set up like this:
>>> car1.other_car is car2 and car2.other_car is car3 and car3.other_car is car1
True
I'd suggest separating the car data structure from the data structure that references a sequence of cars. other_car doesn't really seem like data that strictly belongs in car, but rather represented in some iterable sequence of cars. Thus the simplest and most logically consistent solution would be to define a car, then put it in a sequence of cars.
If you really don't want to use a factory method, then the only real option is to force the user to configure them afterwards. (Taking on-board what you said about potentially wanting loops of dependency in the comments):
class Car:
def __init__(self, position, speed):
self.position = position
self.speed = speed
#staticmethod
def setup(*args):
for car, next in zip(args, args[1:]):
car.other_car = next
args[-1].other_car = args[0]
def main():
...
car1 = Car(pos1, spd1)
car2 = Car(pos2, spd2)
Car.setup(car1, car2)
Another option is to split off the grouping:
class CarGroup(list):
def other_car(self, car):
index = self.index(car)+1
index = 0 if index >= len(self) else index
return self[index]
class Car:
def __init__(self, position, speed, group):
self.position = position
self.speed = speed
self.group = group
self.group.append(self)
#property
def other_car(self):
return self.group.other_car(self)
def main():
...
group = CarGroup()
car1 = Car(pos1, spd1, group)
car2 = Car(pos2, spd2, group)

Categories