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
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."
I'm relatively new to coding and wanted to try my hand at a longer project - A text based RPG game - and I'm scratching my head at classes and objects, can someone point me in a better direction?
>> Error: enemy has no attribute 'attack'
class Character(object):
def __init__(self, name):
self.name = name
self.maxHealth = health
self.health = self.maxHealth
self.attack = attack
self.AC = AC
self.armour = armour
self.strength = strength
self.equipped_weapon = equipped_weapon
self.xp = xp
class player(Character):
def __init__(self, name):
self.name = "KD"
self.maxHealth = 100
self.health = self.maxHealth
self.attack = 15
self.AC = 15
self.armour = 0
self.strength = 15
self.equipped_weapon = "Pistol"
self.xp = 0
class enemy(Character):
def __init__(self, name):
self.name = "X"
self.maxHealth = 60
self.health = self.maxHealth
self.attack = 8
self.AC = 8
self.armour = 0
self.strength = 5
self.xp = 25
enemyIG = enemy
playerIG = player
def player_combat(player, enemy):
in_combat = 1
while in_combat == 1 and player.health > 0:
player_ac_check = (random.randint(0, player.attack + 1))
enemy_ac_check = (random.randint(0, enemy.attack + 1))...
player_combat(playerIG, enemyIG)
You need to instantiate to the class, not assign it.
Change this:
enemyIG = enemy
playerIG = player
to this:
enemyIG = enemy(name = 'enemy1')
playerIG = player(name = 'player1')
This would still endup in an infinite loop, you need some logic for a meaningful end, perhaps decreasing the player health.
while in_combat == 1 and player.health > 0:
player_ac_check = (random.randint(0, player.attack + 1))
enemy_ac_check = (random.randint(0, enemy.attack + 1))
player.health -= 10 # once the health goes below 0, it would end
You haven't initialized the objects, just passed references to the classes. You have to instantiate like so:
enemyIG = enemy(name="Bad Guy")
playerIG = player(name="Good Guy")
An uninitialized class doesn't have attributes unless they're defined outside of __init__
I have this bad error in put for a game I'm trying to code. It's bare bones at the moment, and I'm trying to code the information for one of the enemies the player fights.
class Enemy():
def __init__(self):
super(). __init__ (
self.name = "Goblin" +
self.healthpoints = 12 + # on this line
self.damage = 3)
def isAlive(self):
return self.hp > 0
Do you mean to do this?
class Enemy():
def __init__(self):
self.name = "Goblin"
self.healthpoints = 12
self.damage = 3
super().__init__(name=self.name, healthpoints=self.healthpoints, damage=self.damage)
enter code here
def isAlive(self):
return self.hp > 0
```
self.name = "Goblin" + is a syntax error. You aren't adding anything to "Goblin". The reason it is complaining about the line after is that it is trying to add self.healthpoints = 12 to "Goblin" and you can't add assignment statements.
I think what you want to do is something like this:
def __init__(self):
self.name = "Goblin"
self.healthpoints = 12
self.damage = 3
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'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())