NameError while trying to extend a class - python

I am trying to make a pokemon game. In this game, I am trying to have pokemon (specific ) classes, which extend a pokemon class(general)
for example, Charmander class extends the pokemon class
However, whenever I extend the pokemon, I get a name error, I tried importing pokemon before extending it, and I still got an error
This is my pokemon.py:
from Charmander import *
from Bulbasaur import *
from Turtwig import *
class Pokemon:
def __init__(self, current_hp, attack, defense):
self.name = "PlaceHolder"
self.pokemon_type = "PlaceHolder"
self.current_hp = current_hp
self.attack = attack
self.defense = defense
self.fainted = False
def getName(self):
return self.name
def getType(self):
return self.pokemon_type
def getCurrentHP(self):
return self.current_hp
def getHealth(self):
return self.current_hp
def getAttack(self):
return self.attack
def getDefense(self):
return self.defense
def getFainted(self):
return self.fainted
def printStatus(self):
print(self.name)
print(str(self.current_hp))
def takedamage(self, amount):
self.current_hp -= amount
def tackle(self, opponent):
opponent.current_hp -= self.attack
def die(self, opponent):
self.fainted = True
if self.current_hp == 0:
print("You Lose!")
elif(opponent.current_hp == 0):
print("You win!")
def checkDead(self, opponent):
if self.current_hp == 0 or opponent.current_hp == 0:
self.die(opponent)
def assignPokemon(self, player):
if player == "Charmander":
player = Charmander(200, 20, 20)
if player == "Bulbasaur":
player = Bulbasaur(200, 20, 20)
if player == "Turtwig":
player = Turtwig(200, 20, 20)
return player
This is my Charmander.py:
from pokemon import *
class Charmander(Pokemon):
pass
def __init__(self, current_hp, attack, defense):
self.name = "Charmander"
self.type = "Fire"
self.current_hp = 200
self.attack = 10
self.defense = 10
def ember(self, opponent):
opponent.takeDamage(40)
def will_o_wisp(self, opponent):
return
def flamethrower(self, opponent):
opponent.takeDamage(90)
This is the error I am receiving:
/Users/alex/PycharmProjects/test/venv/bin/python "/Users/alex/Documents/SCSNoonan Computer Science/Slow Pokemon/main.py"
Traceback (most recent call last):
File "/Users/alex/Documents/SCSNoonan Computer Science/Slow Pokemon/main.py", line 1, in
from pokemon import *
File "/Users/alex/Documents/SCSNoonan Computer Science/Slow Pokemon/pokemon.py", line 1, in
from Charmander import *
File "/Users/alex/Documents/SCSNoonan Computer Science/Slow Pokemon/Charmander.py", line 2, in
class Charmander(Pokemon):
NameError: name 'Pokemon' is not defined

This error is probably due to circular imports. Also, the pass statement before your __init__ method inside your Charmander class is useless.
You don't need to do this in your pokemon.py file
from Charmander import *
from Bulbasaur import *
from Turtwig import *
The method assignPokemon doesn't need self parameter so it should either be a staticmethod or be outside of your Pokemon class.
You should put all pokemon classes in a file together and then you could call assignPokemon in another file, for example:
# main.py
from pokemon import Charmander, Bulbasaur, Turtwig
def assignPokemon(player):
if player == "Charmander":
player = Charmander(200, 20, 20)
if player == "Bulbasaur":
player = Bulbasaur(200, 20, 20)
if player == "Turtwig":
player = Turtwig(200, 20, 20)
return player

Related

automatically instantiating objects

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."

Can't seem to pass class variables through functions

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__

print object/instance name in python

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

TypeError: unbound method fight() must be called with Pokemon instance as first argument (got type instance instead)

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)

Ping Pong simulation not correctly triggering function

I'm new to OOP and am practicing putting together a little bit more complex programs using various classes and implementing principles like Inheritance. I've created a Ping-Pong simulation that has a Player class which contains the probability that the player will win their serve. Then I have a PingPong class which is a subclass of the super class RacquetSports. Each instance is a single game, with the ability to change server, and record who won, and whether or not it was a shut-out. Finally, I have a SimStats class whose purpose is to record the stats across "n" number of games.
My problem is that it seems like my play_game function is not correctly firing, when I place a print statement in there it never triggers. My current result when running the whole program is that Player1 has 10 wins no shutouts, and Player2 has zero of both.
Finally, any suggestions on better OO practice would also be appreciated. Here is my player class:
from random import random
class Player(object):
def __init__(self, prob_win):
self.prob = prob_win
self.points = 0
def wins_serve(self):
return self.prob >= random()
def add_point(self):
self.points += 1
def get_score(self):
return self.points
My RacquetSports class:
from abc import ABCMeta, abstractmethod
from player import Player
class RacquetSport(object):
__metaclass__ = ABCMeta
def __init__(self, prob1, prob2):
self.player1 = Player(prob1)
self.player2 = Player(prob2)
self.server = self.player1
def play_game(self):
while not self.game_over():
self.sim_point()
#abstractmethod
def type(self):
pass
def chg_server(self):
if self.server == self.player1:
self.server = self.player2
else:
self.server = self.player1
def sim_point(self):
if self.server.wins_serve():
self.server.add_point()
else:
self.chg_server()
#abstractmethod
def game_over(self):
pass
def get_scores(self):
return self.player1.get_score(), \
self.player2.get_score()
def return_stats(self):
p1_score, p2_score = self.get_scores()
print(p1_score, p2_score)
won = 'p1'
if p2_score > p1_score:
won = 'p2'
return won, self.__shutout(p1_score, p2_score)
#staticmethod
#abstractmethod
def __shutout(score1, score2):
pass
My PingPong and SimStats classes, as well as my calling code:
from racquet import RacquetSport
class PingPong(RacquetSport):
def type(self):
return 'Ping Pong'
def game_over(self):
return self.player1.get_score == 11 or \
self.player2.get_score == 11
#staticmethod
def __shutout(score1, score2):
return abs(score1 - score2) == 11
class SimStats(object):
def __init__(self):
# First field is games won, second is shutouts.
self.gms_won_p1 = [0] * 2
self.gms_won_p2 = [0] * 2
def update(self, game):
won, shutout = game.return_stats()
if won == 'p1':
self.gms_won_p1[0] += 1
if shutout:
self.gms_won_p1[1] += 1
else:
self.gms_won_p2[0] += 1
if shutout:
self.gms_won_p2[1] += 1
def print_results(self):
tot_games = self.gms_won_p1 + self.gms_won_p2
print('Wins for Player 1 = {} Shutouts = {}\n'
'Wins for Player 2 = {} Shutouts = {}'.format(*tot_games))
if __name__ == '__main__':
stats = SimStats()
for x in range(1, 11):
game = PingPong(.5, .5)
stats.update(game)
stats.print_results()
Your first problem is that you never call play_game. My guess is that you intend it to work like this:
if __name__ == '__main__':
stats = SimStats()
for x in range(1, 11):
game = PingPong(.5, .5)
game.play_game()
stats.update(game)
stats.print_results()
Next, you have a bug that will cause the entire game to last forever. Take a look at these lines:
def game_over(self):
return self.player1.get_score == 11 or \
self.player2.get_score == 11
get_score is a function, so you need to call it:
def game_over(self):
return self.player1.get_score() == 11 or \
self.player2.get_score() == 11

Categories

Resources