I'm having trouble with trying to print the stats of the player in a class function. When I run it, it doesn't print.
class Player(object):
def __init__(self, name, hp, dmg, lvl, inventory, speed):
self.name = name
self.hp = hp
self.dmg = dmg
self.lvl = lvl
self.inventory = inventory
self.speed = speed
def printStats(self):
return("Health: " + self.hp + ", Attack Damage: " + self.dmg + ", Level: " + self.lvl + ", Speed: " + self.speed)
link = Player("Link", 10, 3, 1, {}, 3)
link.printStats
If you want to print stats, you must print the stats.
def printStats(self):
print("Health: " + ...)
You also need to actually call the function (notice the trailing parenthesis):
link.printStats()
A somewhat more pythonic solution would be to modify what gets printed when you print the object. You can do that by defining the method __str__. Then, just pass your object to the print command.
class Player(object):
def __init__(self, name, hp, dmg, lvl, inventory, speed):
self.name = name
self.hp = hp
self.dmg = dmg
self.lvl = lvl
self.inventory = inventory
self.speed = speed
def __str__(self):
return "Health: %s Attack Damage: %s Level: %s Speed: %s" % (self.hp, self.dmg, self.lvl, self.speed)
link = Player("Link", 10, 3, 1, {}, 3)
print(link)
Instead you can use __repr__(self) function:
class Player(object):
def __init__(self, name, hp, dmg, lvl, inventory, speed):
self.name = name
self.hp = hp
self.dmg = dmg
self.lvl = lvl
self.inventory = inventory
self.speed = speed
def __repr__(self):
return("Health: " + self.hp + ", Attack Damage: " + self.dmg + ", Level: " + self.lvl + ", Speed: " + self.speed)
link = Player("Link", 10, 3, 1, {}, 3)
print link
When you run a program in IDLE or the REPL, python automatically prints the return value of the function. So replace this:
def printStats(self):
return("Health: " + ...)
with this:
def printStats(self):
print("Health: " + ...)
You also failed to actually call the function (i.e. run).
link.printStats
simply says "Ok, find me the printStats function from link."
You didn't run it, you simply retrieved it.
Try this instead:
link.printStats()
BTW, python convention says that you should not use CamelCase lettering for functions. Use name_with_underscores instead.
depending on what version of python you are running in you'll need to do this
for python 2.7
print link.printStats()
for python 3.x
print(link.printStats())
Related
players_list = [Ani, Paty, Felix, Alex]
class Player:
def __init__(self, name):
self.name = name
self.score = 0
self.vote = 0
self.player_hand = []
self.choice = ''
self.player_hand = []
def player_turn(self):
print(self.name, "'s turn")
def p_vote(self):
print(self.name, " voted")
I tried to iterate over the list, but it always gives me an error: NameError: name 'Ani' is not defined
for player in players_list:
player = Player(str(player))
But doing all the process manually work:
Ani = Player("Ani"), etc
Is there any way that i can automate this process?
First of all the thing you should know, the players_list that you have declared are not containing strings, they are being considered as variables which you have not defined anywhere, and therefore the NameError.
Now, if you want to correct this, and if you actually intend to store objects of Player in players_list, then you can do the following:
players_list = ["Ani", "Paty", "Felix", "Alex"]
class Player:
def __init__(self, name):
self.name = name
self.score = 0
self.vote = 0
self.player_hand = []
self.choice = ''
self.player_hand = []
def player_turn(self):
print(self.name, "'s turn")
def p_vote(self):
print(self.name, " voted")
for i in range(len(players_list)):
players_list[i]=Player(players_list[i])
This will store Player objects in the list you have declared just the thing that you expect to get.
You are having problems with the players not being defined. So players_list = [Ani, Paty, Felix, Alex] will throw an error because the objects Ani, Paty, Felizx, and Alex do not exist.
class Player:
def __init__(self, name):
self.name = name
self.score = 0
self.vote = 0
self.player_hand = []
self.choice = ''
self.player_hand = []
def player_turn(self):
print(self.name, "'s turn")
def p_vote(self):
print(self.name, " voted")
Now, we need to iterate through the list.
players_list = ['Ani', 'Paty', 'Felix', 'Alex']
players = [Player(player) for player in players_list]
Sounds like you're trying to dynamically create variables - write code that writes code.
You could try to use the exec built-in function.
players = ['Ani', 'Paty', 'Felix', 'Alex']
class Player:
def __init__(self, name):
self.name = name
def p_vote(self):
print(self.name + " voted.")
for player in players:
exec( "%s = Player( '%s' )" %(player, player) )
Ani.p_vote()
Although, general internet advice has two points to make:
Be cautious where you use exec.
The Pythonic way is to write out the variables, "explicit is better than implicit."
#Here is the code I currently have:
class Character(object):
def __init__(self, currentHealth, maxHealth, damage, defence, agility):
self.currentHealth = currentHealth
self.maxHealth = maxHealth
self.damage = damage
self.defence = defence
self.agility = agility
class Enemy(Character):
def __init__(self, drop):
Character.__init__(self, currentHealth, maxHealth, damage, defence, agility)
self.drop = drop
def checkHealth(self):
print("The enemies health is: " + str(self.currentHealth))
def inspectStats(self):
print("The enemies health is: " + str(self.currentHealth))
print("The enemies attack is: " + str(self.damage))
print("The enemies defence is: " + str(self.defence))
print("The enemies evasiveness is: " + str(self.agility))
class Player(Character):
def __init__(self, currentHealth, maxHealth, damage, defence, agility, gold):
self.currentHealth = currentHealth
self.maxHealth = maxHealth
self.damage = damage
self.defence = defence
self.agility = agility
self.gold = gold
def checkHealth(self):
print("Your current health is: " + str(self.currentHealth))
def inspectStats(self):
print("Your current health is: " + str(self.currentHealth))
print("Your max health is: " + str(self.maxHealth))
print("Your attack is: " + str(self.damage))
print("Your defence is: " + str(self.defence))
print("Your agility is: " + str(self.agility))
print("Your gold is: " + str(self.gold))
bob = Player(15, 15, 5, 6, 7, 70)
spider = Enemy(10, 10, 2, 1, 5, 'silk')
spider.inspectStats()
I haven't been able to get this code working, I have searched online and have found mild success with this website: http://www.jesshamrick.com/2011/05/18/an-introduction-to-classes-and-inheritance-in-python/
It appears, however, that the code still isn't working. It would be greatly appreciated if someone could tell me how I am supposed to do inheritance.
(I know that there is going to be a subclass of enemy so it would be helpful if that was taken into consideration).
Ok , so , your child class which is Enemy got in method definition that it only takes 2 arguments self and drop.
So if You want to make it able to recieve more params you must provide some placeholder for it. The naive way is just write all the needed params in place. But lats say in future you will extend the number of the params the Character class is taking. To make the solution more freindly we can add the *args varibale as param. This vairable (args isnt obligatory name the crucial here is the * operator standing before it) will "catch" all the params which you provide after the drop param. The star operator doesn't care how many params You pass. It will try to take as many as possible. These stored params can now be unpacked to the parent __init__ method like this :
class Enemy(Character):
# the *args will "catch" all the positional
# parameters passed to this class
def __init__(self, drop, *args):
# now we are using unpacking to
# apply all positional params holded in args to parent init method
Character.__init__(self, *args)
self.drop = drop
# Now You must remeber to pass the the init the
# child argument which is drop
# + all the parent class positional args (currentHealth, ...)
enemy = Enemy(True,...)
Your Enemy init function doesn't have the right number of parameters. Try this:
class Enemy(Character):
def __init__(self, currentHealth, maxHealth, damage, defence, agility, drop):
super(Enemy, self).__init__(currentHealth, maxHealth, damage, defence, agility)
self.drop = drop
For more details about the "super" keyword, you can go there
I really never bothered to learn classes in Python because all the docs I find are a bit too technical for me. So, yet again I have sat down to try to conquer them. I would love to be able to use classes for the text based games that I make, so that is how I try every time.
My class code (its messy now because I have been trying everything I can think of) is
class enemy:
def __init__(self, name, weapon, hp, attack, defense, xp):
self.self = self
self.name = name
self.hp = hp
self.attack = attack
self.defense = defense
self.xp = xp
#self.attack_text1 = attack_text1
self.attack_text1 = name, " attacks you with ", weapon, "."
#self.attack_damage = attack_damage
self.attack_damage = random.randint(0,2) + attack
#self.total_damage = total_damage
self.total_damage = self.attack_damage - player.defense
if self.total_damage < 1:
self.total_damage = 0
#self.attack_text2 = attack_text2
self.attack_text2 = name, " deals ", self.total_damage, " to you."
#staticmethod #tried this from a solution found on stack overflow
def combat_roll(self):
self.roll = random.randrange(0,20) + attack
combat_roll(self)
I have a function called combat() that pits the player against an instance of the enemy class.
The instance is called like in that function:
def combat():
goblin_weapon = weapon("goblin dagger", 1, 5)
goblin = enemy("ugly goblin", goblin_weapon, 3,2,1,150)
goblin_damage = goblin.attack - player.defense
print "a ", goblin.name, " attacks you with ", goblin_weapon, "."
print goblin.combat_roll
if goblin.roll > player.defense:
print goblin.name, "does ", goblin_damage, " damage."
else:
print goblin.name, "misses."
My goal is essentially somewhat of a d20 feel to the combat. attack bonus + d20 rolls vs armor class. I was hoping that the enemy class could have its own function that could handle its own dice rolls.
I've lost the original state of my code. I have checked google and searched here for solutions but none of them worked. I am sure it is because I haven't seen the solution in a way that works with my brain, because this can't be that complicated. Why can't I just call the function like I reference class variables?
enemy.combat_roll()
you know?
Anyway, thanks for the help!
You're declaring the method only within __init__, instead of within enemy. To my understanding, it will only be available if you declare it within the enemy class itself.
class enemy:
def __init__(self, name, weapon, hp, attack, defense, xp):
self.self = self
self.name = name
self.hp = hp
self.attack = attack
self.defense = defense
self.xp = xp
#self.attack_text1 = attack_text1
self.attack_text1 = name, " attacks you with ", weapon, "."
#self.attack_damage = attack_damage
self.attack_damage = random.randint(0,2) + attack
#self.total_damage = total_damage
self.total_damage = self.attack_damage - player.defense
if self.total_damage < 1:
self.total_damage = 0
#self.attack_text2 = attack_text2
self.attack_text2 = name, " deals ", self.total_damage, " to you."
combat_roll(self)
def combat_roll(self):
self.roll = random.randrange(0,20) + attack
As you say, your code is a little all over the place, and it isn't entirely complete. I've tried to rewrite and fill it out a bit in the spirit of what I think you were going for:
import random
#dice roll for dealing damage as a global function
def get_damage(dice_size, bonus_damage):
return random.randrange(dice_size) + bonus_damage
#class for a player
class Player:
#initialises the player's name, defense value and hp
def __init__(self, name, defense, hp):
self.name = name
self.defense = defense
self.hp = hp
#when something wants a string representation of a player (like format()
#might) it just uses the player's name
def __str__(self):
return self.name
#a method where a player takes damage from some enemy (if it quacks like an
#enemy..). This is where your attack_text2 has gone.
def take_damage(self, enemy, dmg):
self.hp -= dmg
print("{} deals {} damage to {}".format(enemy, dmg, self))
#class for a weapon
class Weapon:
#__init__ taking 4 arguments, like in your code, except it wasn't clear what
#the last two arguments were.
def __init__(self, name, foo, bar):
self.name = name
self.foo = foo
self.bar = bar
#as with Player
def __str__(self):
return self.name
#class for an enemy
class Enemy:
#this has changed: init only needs to *init*ialise the object not do any
#more, so all it does is stored relevant info as a field.
def __init__(self, name, weapon, hp, attack, defense, xp):
self.self = self
self.name = name
self.weapon = weapon
self.hp = hp
self.attack = attack
self.defense = defense
self.xp = xp
#as with Weapon
def __str__(self):
return self.name
#this is roughly where the second half of your init has gone. Engages in
#combat with a player, generating a random amount of damage, and doing all
#of the defense/attack malarkey. The damage is not stored as a field (using
#self.) as it is only needed for the duration of the combat
def combat(self, player):
print("{} attacks {} with {}.".format(self, player, self.weapon))
damage = get_damage(20, self.attack)
total_damage = damage - player.defense
if total_damage < 0:
total_damage = 0
player.take_damage(self, total_damage)
#function constructing a couple of objects and using them to do a 'fight'
#I've used some key word arguments with the goblin and the player. I'd advise
#you to keep doing the same, as it helps a lot with clarity.
def play():
dagger = Weapon("a goblin dagger", 1, 5)
goblin = Enemy("an ugly goblin", dagger, hp=3, attack=2, defense=1, xp=150)
aragorn = Player("Aragorn", defense=3, hp=100)
goblin.combat(aragorn)
print("{} now has {} hp".format(aragorn, aragorn.hp))
play()
I've included some comments trying to explain what's changed and what does what, and why, hopefully.
I hope it's stuck to your vision of the code. The main changes were to just refactor your bits of code around a bit. In your __init__ for the enemy, you originally had the code that's now ended up in Enemy.combat, for example. You also hadn't included a Weapon or Player class, although your code constructed a weapon and referred to player, so I've added those in. Let me know if you'd like any more clarification.
Here is a sample of this code in action:
an ugly goblin attacks Aragorn with a goblin dagger.
an ugly goblin deals 10 damage to Aragorn
Aragorn now has 90 hp
I was wondering if there is a way to print the object name in python as a string. For example I want to be able to say ENEMY1 has 2 hp left or ENEMY2 has 4 hp left. Is there a way of doing that?\
class badguy:
def __init__(self):
self.hp = 4
def attack(self):
print("hit")
self.hp -= 1
def still_alive(self):
if self.hp <=0:
print("enemy destroyed")
else :
print (str(self.hp) + " hp left")
# creating objects
enemy1 = badguy()
enemy2 = badguy()
enemy1.attack()
enemy1.attack()
enemy1.still_alive()
enemy2.still_alive()
A much better design principle is not to rely on the specific name of the object as shown below:
class badguy(object):
def __init__(self):
pass
b = badguy()
print b
>>> <__main__.badguy object at 0x7f2089a74e50> # Not a great name huh? :D
This can lead to a whole wealth of issues with assignment binding, referencing, and most importantly does not allow you to name your objects per user or program choice.
Instead add an instance variable to your class called self._name (9.6 Classes - Private Variables) or self.name if you want to allow access outside the scope of the class (in this example, you can name it anything). Not only is this more Object-Oriented design, but now you can implement methods like __hash__ to be able to create a hash based on a name for example to use an object as a key (there are many more reasons why this design choice is better!).
class badguy(object):
def __init__(self, name=None):
self.hp = 4
self._name = name
#property
def name(self):
return self._name
#name.setter
def name(self, name):
self._name = name
def attack(self):
print("hit")
self.hp -= 1
def still_alive(self):
if self.hp <=0:
print("enemy destroyed")
else :
print ("{} has {} hp left.".format(self.name, self.hp))
Sample output:
b = badguy('Enemy 1')
print b.name
>>> Enemy 1
b.still_alive()
>>> Enemy 1 has 4 hp left.
b.name = 'Enemy One' # Changing our object's name.
b.still_alive()
>>> Enemy One has 4 hp left.
You'd have to first give them names. E.g.
class badguy:
def __init__(self, name):
self.hp = 4
self.name = name
def attack(self):
print("hit")
self.hp -= 1
def still_alive(self):
if self.hp <=0:
print("enemy destroyed")
else :
print (self.name + " has " + str(self.hp) + " hp left")
# creating objects
enemy1 = badguy('ENEMY1')
enemy2 = badguy('ENEMY2')
enemy1.attack()
enemy1.attack()
enemy1.still_alive()
enemy2.still_alive()
I have posted a complete solution here:
https://stackoverflow.com/a/49331683/7386061
It works without parameters. For example you could just do:
class badguy(RememberInstanceCreationInfo):
def __init__(self):
super().__init__()
self.hp = 4
def attack(self):
print("hit")
self.hp -= 1
def still_alive(self):
if self.hp <=0:
print("enemy destroyed")
else :
print (self.creation_name + " has " + str(self.hp) + " hp left")
enemy1 = badguy()
enemy2 = badguy()
enemy1.attack()
enemy1.attack()
enemy1.still_alive()
enemy2.still_alive()
out: hit
out: hit
out: enemy1 has 2 hp left
out: enemy2 has 4 hp left
This is my code:
# pokemon1
class Pokemon(object):
def __init__(self,name,hp,damage):
self.name = name
self.hp = hp
self.damage = damage
def fight(self,other):
if(self.hp > 0):
print("%s did %d damage to %s"%(self.name,self.damage,other.name))
other.hp -= self.damage
if (other.hp > 0):
print("%s has %d hp left" % (other.name, other.hp))
else:
print("%s has died" % (other.name))
return other.fight(self)
else:
print("%s wins! (%d hp left)"%(other.name,other.hp))
return other,self
class pikachu(Pokemon):
def __init__(self):
super(pikachu, self).__init__('pikachu', 100, 10)
class pidgy(Pokemon):
def __init__(self):
super(pidgy, self).__init__('pidgy', 200, 12)
#main
import pokemon1
pikachu = pokemon1.pikachu
pidgy = pokemon1.pidgy
p = pokemon1.Pokemon
p.fight(pikachu,pidgy)
You need to call Pokemon(), not Pokemon, in your second-last line to invoke the constructor.
Reinderien was right, but I tried your code and found a different problem, you designed the class differently to how you are trying to use it.
This code should work instead:
pikachu = pokemon1.pikachu
pidgy = pokemon1.pidgy
pikachu.fight(pidgy)