Stuck on a simple if statement Python 3 - python

I'm very new to Python, and I've been wondering where to ask this question.
Well, I'm having a small difficulty with this small if statement.
I've broken it down, as the full if statement will be used in this small text RPG game.
health = 50
if(health > 100):
health = 100
print (health)
print (health)
What I'm trying to do is make it so the Health will never go above 100.
But typing
>>> health = 150
>>> print (health)
health = 150
And the IF statement hasn't been called.
I know this is probably a really easy fix for any experienced Python developer, but I simply cannot wrap my head around it.
Thanks,
Amos.

Your if statement is not automatically run when you set health to 150. You'll need to explicitly execute it again to limit your health value.
You could make that a function:
def limit_health(health):
if health < 0:
health = 0
if health > 100:
health = 100
return health
health = limit_health(150)
or you could just use min() to prevent health from going over 100:
health = min(health, 100)
If you are not averse to using classes, make health a property of the player:
class Player(object):
MAX_HEALTH = 100
def __init__(self):
# players start out with maximum health
self.health = self.MAX_HEALTH
# other things players track and can do
#property
def health(self):
return self._health
#health.setter
def health(self, new_health):
# limit health to MAX_HEALTH at most
self._health = min(new_health, self.MAX_HEALTH)
then whenever you set player.health it'll be automatically limited for you.

Related

Classes and Objects: How do I set a boolean from a method to create "chance" with a poison status, or use later for dodge and other reusables

How do I set a boolean from a method to create "chance" with a poison status, or use later for dodge and other reusable.
Just now learning Simple Inheritance with Super() and not yet gotten to Complex Inheritance. Not sure if that would make a difference in how I could of coded this but using what I know, here is what I have.
What I am trying to do is create a method inside the Hero Class, and make the hero only be poisoned if a condition is met or a boolean is passed. I keep getting an issue with the logic. Still new to programming.
I've re-written the code multiple times using Idle for speed and it just keeps giving me problems, even when i place the for-loop inside the hero.PoisionedCheck(True) I only get the displayed text and not the forloop activated. Then I will get an error that "amount" parameter is not defined or called before assignment, then when I fix that I will get that scorpion.health and scorpion.energy is not defined. I'm running in circles.
Thank you for reading.
import time
class Monster:
name= 'Monster'
def __init__(self,health, energy):
self.health = health
self.energy = energy
def attack(self, amount):
print('Monster has attacked')
print(f'{amount} damage was delt!')
self.energy -= 20
def move(self,speed):
print(f'{self.name} has moved, at {speed} speed')
class Scorpion(Monster):
name='Scorpion'
def __init__(self, health, energy):
super().__init__(health, energy)
def attack(self, amount):
print('Scorpion has attacked')
print('Poison has take effect!')
# Loops Poison display repeated with time delay.
# for repeater amount of times.
repeater = 5
for poison in range(repeater):
poison = 0
amount = poison + amount
print(f'Poisoned: {amount} damage')
time.sleep(0.5)
poison = repeater
amount *= poison
print(f'Poison did a total damage of {amount} to {hero.name}')
hero.health -= amount
class Hero(Monster):
name = 'Rockwood'
def __init__(self, health, energy) -> None:
self.health = health
self.energy = energy
# How do I use this in a boolean to check Scorpion attack?
# Lets say later adding *import random* later to determine chances of poison.
# def PoisonedCheck(self, posioned):
# self.poisoned = posioned
# if posioned == True:
# print("Testing if become posioned- For loop goes after here to create damage.")
# posioned = True
# else:
# print('Became else.. ')
# posioned = False
monster = Monster(health=100, energy=100)
scorpion = Scorpion(health = 200, energy = 150)
hero = Hero(health=100, energy=100)
scorpion.attack(3)
print()
scorpion.move(110)
hero.move(50)
print(f"{hero.name} has {hero.health} health remaining. ")
print()
To be honest, I am not really sure what you are trying to achieve, hopefully this answers your question or gets you going.
Firstly I would suggest adding a target parameter to Scorpion's attack behaviour and modifying it's behaviour. That way you can define multiple heroes and have them combat the scorpion, for example:
scorpion = Scorpion(health = 200, energy = 150)
hero_one = Hero(health=100, energy=100)
hero_two = Hero(health=200, energy=100)
scorpion.attack(hero_one)
scorpion.attack(hero_two)
Secondly, Scorpion doesn't seem to lose energy after attacking and doesn't deal initial damage. You could fix that by changing Scorpion attack behaviour to first call parent attack function:
class Scorpion(Monster):
...
def attack(self, amount, target):
super().attack(amount, target)
print('Poison has take effect!')
...
But Monster attack behaviour doesn't accept second argument, so my suggestion is to modify Monster's attack function with second parameter to also deal initial damage to target (and correctly subtract target's health with damage amount):
class Monster:
...
def attack(self, amount, target):
print(f'{self.name} has attacked')
print(f'{amount} damage was delt!')
target.health -= amount
self.energy -= 20
To track poisoned status, easiest you can do is to introduce state in Monster class constructor called poisoned and set it to False (initial state is that monster and every child object is not poisoned).
Then you can change target's poisoned state in Scorpion's attack method, like so:
class Scorpion(Monster):
...
def attack(self, amount, target):
...
target.poisoned = True
...
This way you can see if one of Heroes is poisoned, like so:
print(hero_one.poisoned) --> False or True (if attacked by scorpion)
To calculate a chance (lets say 50%) if Scorpion's attack will poison the target or not, extract poison application behaviour into separate private function and modify it like this:
class Scorpion(Monster):
...
def attack(self, amount, target):
super().attack(amount, target)
self.__poison_target(amount, target)
def __poison_target(self, amount, target):
# A coin toss to decide if target will be poisoned or not.
should_apply_poison = random.randint(0, 1) == 1
if should_apply_poison:
print('Poison has take effect!')
target.poisoned = True
# Loops Poison display repeated with time delay.
# for repeater amount of times.
repeater = 5
for poison in range(repeater):
poison = 0
amount = poison + amount
print(f'Poisoned: {amount} damage')
time.sleep(0.5)
poison = repeater
amount *= poison
print(f'Poison did a total damage of {amount} to {target.name}')
target.health -= amount
...
Or you can delegate damage dealing behaviour from Scorpion to Hero by creating abstract class Poisonable which you can use to check if the target is Poisonable (in your case - Hero inherits from Poisonable). This way Scorpion class doesn't care if target is successfuly poisoned or not.
Poisonable class is contract which all classes that inherit from it must abide by (e.g. implement their own version of resistance, damage taking from poison). This way every poisoned creature can react differently.
class Poison:
def __init__(self):
self.damage_per_tick = 5
self.ticks = 3
class Scorpion(Monster):
name = 'Scorpion'
def __init__(self, health, energy):
super().__init__(health, energy)
self.poison = Poison()
def attack(self, amount, target):
super().attack(amount, target)
self.__poison_target(target)
def __poison_target(self, target):
if isinstance(target, Poisonable):
target.suffer_poison_damage(self.poison)
class Poisonable(ABC):
#abc.abstractmethod
def resist_poison(self) -> bool:
pass
#abc.abstractmethod
def suffer_poison_damage(self, poison: Poison) -> None:
pass
class Hero(Monster, Poisonable, ABC):
name = 'Rockwood'
def __init__(self, health, energy) -> None:
super().__init__(health, energy)
def resist_poison(self) -> bool:
# resist poison chance
return random.randint(0, 1) == 1
def suffer_poison_damage(self, poison: Poison) -> None:
if self.resist_poison():
pass
else:
print('Poison has take effect!')
# Loops Poison display repeated with time delay.
# for repeater amount of times.
total_amount = 0
for poison_tick in range(poison.ticks):
total_amount += poison.damage_per_tick
print(f'Poisoned: {poison.damage_per_tick} damage')
time.sleep(0.5)
print(f'Poison did a total damage of {total_amount} to {self.name}')
self.health -= total_amount

Python Game Planner - Unexpected Behavior from Delayed Function Execution - Scope/Binding/Closure Issue? [duplicate]

This question already has answers here:
What do lambda function closures capture?
(7 answers)
Creating functions (or lambdas) in a loop (or comprehension)
(6 answers)
Closed 6 months ago.
I am implementing a decision-making pattern for enemies in my turn-based game. In order to help understand the code (I hope!), I'll explain the pattern it's implementing:
When an enemy is instructed to take_a_turn(), they make a plan to take every action available to them on every valid target (e.g. attack player, heal self, heal ally) in the fight.
Each plan consists of an action (function) and a score (int).
Enemies have goals with numeric values that influence the score of the plans they make. For example, one enemy may only have the goal of hurting players and so will never use a healing ability. Another enemy may have both goals, but favor hurting players more than healing.
When plans are made, scores are weighted by various things. For example, an enemy may favor hurting players more than healing allies based on its goals, but if a specific ally's health is critically low, the value of healing that ally may be high enough that the plan is favored temporarily above smacking players.
When a viable plan is discovered, the function (e.g. the attack or heal spell) and its arguments (the enemy using it, the target, the state of the fight) are assigned to the plan action variable to be invoked later, if the plan is selected.
Once the enemy has made every viable plan, they are sorted by score and the highest score plan is chosen. This is the "best" thing the enemy could do that turn based on their abilities, goals, and the current state of the fight. The chosen plan's action variable is then executed, causing the enemy to do the thing.
This system works well. I ported it successfully from a previous game I wrote in C#. When the function is assigned to the plan's action, in C#, a lambda is used to early-bind the arguments (user, target, fight state).
Everything in Python works correctly... except it executes the wrong action (it appears to execute the last-planned action), even though it selects the correct plan (the 2nd of 3, in my test case) and the selected plan debug text printed out is correct. I believe this may be related to python scope and binding differences from C#, which I have researched extensively and tried several different solutions (lambda, inline function, partial, different argument constructions) but all behave identically. Unfortunately, the plan action variable, which is assigned a function, doesn't visualize in my IDE's (pycharm) debugger, so I can't explicitly see it change while stepping through execution. Here's the relevant code. I've omitted references that aren't material to keep it shorter, but if any references I skip are possibly useful, comment and I'll add them.
Enemy, with all their attendant decision-making logic:
class GoalType(Enum):
damage_player = 1
debuff_player = 2 #not used in this example
heal_ally = 3
buff_ally = 4 # not used in this example
summon = 5 # not used in this example
class Goal:
def __init__(self, goal_type: GoalType, value: int):
self.goal_type = goal_type
self.value = value
# this method looks like overkill, but several future goals have multiple contributor types
#staticmethod
def get_contributor_effects_by_goal_type(goal_type: GoalType):
if goal_type == GoalType.damage_player:
contribs = [EffectType.damage_health]
elif goal_type == GoalType.heal_ally:
contribs = [EffectType.restore_health]
else:
raise Exception(f'GoalType {goal_type} has no configured contributing effects')
return contribs
class Plan:
def __init__(self):
self.action = None
self.debug = ''
self.score = 0
class Enemy:
# I omitted all the enemy member variables here not related to the problem, for brevity.
# AI
self.actions = actions
self.goals = goals
def take_a_turn(self, fight):
plans = self.get_action_plans(fight)
if len(plans) > 0:
print(f'{self.name}\'s plans:')
for plan in plans:
print(': ' + plan.debug)
plans.sort(key=lambda x: x.score, reverse=True)
the_plan = plans[0]
print(f'The chosen plan is: --{the_plan.debug}-- w/ score {the_plan.score}')
return the_plan.action()
else:
return f'{self.name} took no action.'
def get_action_plans(self, fight):
plans = self.get_kill_player_action_plans(fight)
if len(plans) > 0:
return plans
# damage_player goal
goal = [x for x in self.goals if x.goal_type == GoalType.damage_player]
if len(goal) > 0:
plans += self.get_damage_player_plans(goal[0], fight)
# heal_ally goal
goal = [x for x in self.goals if x.goal_type == GoalType.heal_ally]
if len(goal) > 0:
plans += self.get_heal_ally_plans(goal[0], fight)
return plans
def get_damage_player_plans(self, goal, fight):
plans = []
for action in self.actions:
if action.targets_players and action.is_usable(fight.states):
effects = list(filter(lambda effect: effect.type == EffectType.damage_health, action.effects))
if len(effects) > 0:
for character in fight.characters:
dmg = character.estimate_damage_from_enemy_action(self, action)
plan = Plan()
plan.score = goal.value + int(100.0 * dmg / character.health)
plan.action = lambda: action.do(user=self, target=character, fight=fight)
plan.debug = f'damage {character.name} w/ {action.name} score {plan.score}'
plans.append(plan)
return plans
def get_heal_ally_plans(self, goal, fight):
plans = []
for action in self.actions:
if action.targets_allies and action.is_usable(fight.states):
effects = list(filter(lambda effect: effect.type == EffectType.restore_health, action.effects))
if len(effects) > 0:
for enemy in fight.enemies:
plan = Plan()
plan.score = goal.value + 100 - int(enemy.current_health / enemy.health * 100)
plan.action = lambda: action.do(user=self, target=enemy, fight=fight)
plan.debug = f'heal {enemy.name} w/ {action.name} score {plan.score}'
plans.append(plan)
return plans
The Enemy used for testing--ignore all the numbers, which are just various stats
enemies = {
'slime': Enemy('Slime', 1, 0.3, 1, 0.3, 1, 0.3, 1, 0.3, 10, 0.1, 5, 0.2, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
[SingleTargetAttack('Headbutt', '', 0, 0.05,
[SpellEffect(EffectType.damage_health, Elements.earth, 1, 4)]),
SingleTargetHeal('Regenerate', '', 3,
[SpellEffect(EffectType.restore_health, Elements.water, 2, 5)])],
[Goal(GoalType.damage_player, 500), Goal(GoalType.heal_ally, 450)]),
}
How an ability and its do() function is defined
class SingleTargetHeal(Action):
def __init__(self, name: str, description: str, cooldown: int, effects: [SpellEffect]):
for effect in effects:
if effect.type != EffectType.restore_health:
raise Exception(f'SingleTargetHeal {name} has an unsupported effect type {effect.type}')
super().__init__()
self.name = name
self.description = description
self.cooldown = cooldown
self.effects = effects
self.targets_players = False
self.targets_allies = True
self.area = 0
self.area_modifiable = False
def do(self, user, target, fight):
out = f'{user.name} used {self.name} on {target.name}.'
targets = [target]
if self.area > 0:
i = self.area
while i > 0:
if fight.enemies.index(target) + i <= len(fight.enemies) - 1:
targets.append(fight.enemies.index(target) + i)
if fight.enemies.index(target) - i > 0:
targets.insert(0, fight.enemies.index(target) - i)
i -= 1
for target in targets:
for effect in self.effects:
heal = target.restore_health(random.randint(effect.min, effect.max), user)
out += f'\n{target.name} regained {heal} health.'
return out
The base class, Action, defines is_usable() which definitely works correctly. The SingleTargetAttack action is essentially the same as SingleTargetHeal, but attacks players rather than healing enemies. It works, because if I remove the Regenerate spell and the heal_ally goal, the enemy can only make on plan, the attack, and does so correctly.
The debug statements from the planner
Slime's plans:
: damage Player w/ Headbutt score 502
: heal Slime w/ Regenerate score 450
The chosen plan is: --damage justindz#4247 w/ Headbutt score 502-- w/ score 502
What actually happens
Pico Slime goes next.
Pico Slime used Regenerate on you.
You regained 3 health.
As you can see, when the chosen plan's action is invoked, the enemy actually uses Regenerate on the player. Argh. That should not be possible, because it is not one of the valid plans, hence my suspicion that it is scope/binding-related. What am I missing?

How to call a variable from one function into another function?

Note: this is a very long question.
I'm practicing python by making a game. I need to take a variable from another function (that I called spawn()) and use in a different function (that I called damage_taken()).
This is the file enemy.py. Its main job is to spawn an enemy:
import random
import player
class Enemy(object):
def types(self):
type = ["slime", "ghost", "demon"]
enemy = random.choice(type)
return enemy
class Slime(Enemy):
def types(self):
colour = ["red", "green", "blue"]
type = random.choice(colour)
return type
def health(self):
health = random.randint(1,5)
return health
class Ghost(Enemy):
def types(self):
form = ["spirit", "spectre", "phantom"]
type = random.choice(form)
return type
def health(self):
health = random.randint(10,30)
return health
class Demon(Enemy):
def types(self):
being = ["demon", "hell hound", "wendigo"]
type = random.choice(being)
return type
def health(self):
health = random.randint(15,35)
return health
This is the important code. I need to take the variable health from this function and use it in another function.
def spawn():
enemy = Enemy()
bad = enemy.types()
if bad == "slime":
slime = Slime()
target = slime.types()
health = slime.health()
print(f"A {target} {bad} has appeared. It has {health} HP")
return health
elif bad == "ghost":
ghost = Ghost()
target = ghost.types()
health = ghost.health()
print(f"A {target} has appeared. It has {health} HP")
return health
elif bad == "demon":
demon = Demon()
target = demon.types()
health = demon.health()
print(f"A {target} has appeared. It has {health} HP")
return health
This is where i am struggling. I am trying to take the variable health from the function spawn() and use it in the following function. However, it keeps on telling me health does not exist. How do i take a variable from another function and use it in this function.
def damage_taken():
spawn()
health = spawn.health - player.fight()
return health
damage_taken()
The code
spawn.health
is my failed attempt at trying to call the variable into the function.
The code:
player.fight()
is calling a function from a different file called player.py. Its main purpose is to deal with mechanics related to the player such as creating the character and deciding how much damage they deal.
If I well understood your question you just need to assign the return value from your spawn function into a variable:
def damage_taken():
spawn_health = spawn()
health = spawn_health - player.fight()
return health
I'm guessing that you would actually rather the spawn function, return the enemy object, rather than the health of the enemy, so I would recommend the following:
def spawn():
enemy = Enemy()
bad = enemy.types()
if bad == "slime":
enemy = Slime() # each of these now is assigned to the same variable name, "enemy"
target = slime.types()
health = slime.health()
print(f"A {target} {bad} has appeared. It has {health} HP")
elif bad == "ghost":
enemy = Ghost()
target = ghost.types()
health = ghost.health()
print(f"A {target} has appeared. It has {health} HP")
elif bad == "demon":
enemy = Demon()
target = demon.types()
health = demon.health()
print(f"A {target} has appeared. It has {health} HP")
return enemy
def damage_taken():
enemy = spawn()
health = enemy.health - player.fight()
return health
damage_taken()
now, there is still the problem that the enemy object will be entirely dropped after damage_taken() is called. If you want the enemy to persist, you likely will want to initialize both player and enemy outside of the scope of the damage_taken function. Something more like this:
enemy = spawn()
damage_taken(enemy)

Python dictionary nested within method auto-executes all values (methods) when outer method is called

I'm working on a simple skeleton for a game, and in an effort to try and be more "pythonic", I'm using objects/classes/dictionaries to try and capture all my actions/behaviors (as methods over functions, etc).
For some reason, every time I execute the method 'act' within the class "Player", the dictionary embedded within act runs all of its values (which are, in turn, methods from within the same instance of the class "Player"). In other words, the player chooses "attack, heal, and flee" every time, all at once, before being prompted.
I'm sure there's a simple explanation, but I've been looking for hours and can't find another example of someone's dictionary auto-running all the methods embedded within. Can you help?
Thanks!
- Jake
from random import randint
### BEGIN ALL CLASSES HERE
# To be used for all game objects (living and non-living)
class gameObject(object):
def __init__(self, name):
self.name = name
# To be used for all characters who can act in some way/be killed/change
class livingThing(gameObject):
def __init__(self, name, HP=1):
self.name = name
self.HP = HP
# The playable character(s)
class Player(livingThing):
def __init__(self,name="The Stranger", HP=4, MP=5, strength=1, intellect=1, spirit=1, luck=5, gil=6):
self.name = name
self.HP = HP
self.MP = MP
self.gil = gil
self.strength = strength
self.intellect = intellect
self.spirit = spirit
self.luck = luck
def act(player, enemy):
actions = {
"attack" : player.attack(enemy),
"heal" : player.heal(enemy),
"flee" : player.flee()
}
#Takes input from the player
decision = input("What would you like to do? ")
if decision.lower() in actions:
actions[decision.lower()]
else:
print("That didn't work! Try again.")
# Prints both player and enemy HP
def printHP(player, enemy):
print("{0}'s' HP: {1} \n{2}'s HP: {3}".format(player.name, player.HP, enemy.name, enemy.HP))
# Allows the player to attack an enemy (currently functional)
def attack(player, enemy):
enemy.HP -= player.strength
print("You strike {0} for {1} damage!".format(enemy.name, player.strength))
player.printHP(enemy)
# Allows the player to heal a certain amount of health based on its "spirit" stat (currently functional)
def heal(player, enemy):
healed = randint(0, player.spirit)
player.HP += healed
print("You've healed for {0}!".format(healed))
player.printHP(enemy)
#Allows the player to attempt to run away
def flee(player):
randluck = randint(0, player.luck)
if randluck > 3:
print("You successfully escaped!")
return player.HP
else:
print("You weren't able to escape!")
# Anything that can act with/against the player
class Actor(livingThing):
def __init__(self, name="Unknown Entity", HP=10, MP=2, gil=3):
self. name = name
self.HP = HP
self.MP = MP
self.gil = gil
### END ALL CLASSES ###
### DICTIONARIES CONTAINING ACTIONS ###
### CHARACTERS ###
fighter = Player()
monster = Actor()
fighter.act(monster)
I see the problem. When you are executing Python code, and you have a dictionary as you do, Python evaluates the dictionary fully. If you wanted your values (in your key:value) pairs to be the results of those methods, this is surely one way to do it.
In your case, what you can do is reference the function itself, and not invoke it. You can do this by getting rid of the parentheses, like this:
player.attack
instead of
player.attack()
Then, to call the function you can do something like
actions[decision.lower()](enemy)
Since one of your functions, flee, doesn't accept any parameters, you could give flee a parameter that you simply don't use in the function. If you were designing many many methods that your player can act with, then one strategy would be to give them all only named parameters, like this:
def f1(enemy=None,something=None,foo=None):
if enemy is None:
raise Exception("enemy cannot be None")
#process_enemy
If however, you also have a very high amount of parameters, then you could do this:
def attack(**kwargs):
#kwargs is a dictionary of parameters provided to the function
enemy = kwargs.get('enemy',None)
if enemy is None:
raise Exception("enemy cannot be None")
def eat(**kwargs):
food = kwargs.get('food',None)
if enemy is None:
raise Exception("food cannot be None")
attack(enemy="someenemyobject")
eat(food="somefoodobject")
attack() # raises Exception
attack(food="somefoodobject") # raises Exception
food(enemy="someenemyobject") # raises Exception
food(food="somefoodobject",enemy="someenemyobject") # does not raise Exception

Python: Pokemon battle (classes, functions)

I just started learning python and I am hoping you guys can help me comprehend things a little better. If you have ever played a pokemon game for the gameboy you'll understand more as to what I am trying to do. I started off with a text adventure where you do simple stuff, but now I am at the point of pokemon battling eachother. So this is what I am trying to achieve.
Pokemon battle starts
You attack target
Target loses HP and attacks back
First one to 0 hp loses
Of course all of this is printed out.
This is what I have for the battle so far, I am not sure how accurate I am right now. Just really looking to see how close I am to doing this correctly.
class Pokemon(object):
sName = "pidgy"
nAttack = 5
nHealth = 10
nEvasion = 1
def __init__(self, name, atk, hp, evd):
self.sName = name
self.nAttack = atk
self.nHealth = hp
self.nEvasion = evd
def fight(target, self):
target.nHealth - self.nAttack
def battle():
print "A wild appeared"
#pikachu = Pokemon("Pikafaggot", 18, 80, 21)
pidgy = Pokemon("Pidgy", 18, 80, 21)
pidgy.fight(pikachu)
#pikachu.fight(pidgy)
Full code here: http://pastebin.com/ikmRuE5z
I am also looking for advice on how to manage variables; I seem to be having a grocery list of variables at the top and I assume that is not good practice, where should they go?
If I was to have fight as a instance method (which I'm not sure I would), I would probably code it up something like this:
class Pokemon(object):
def __init__(self,name,hp,damage):
self.name = name #pokemon name
self.hp = hp #hit-points of this particular pokemon
self.damage = damage #amount of damage this pokemon does every attack
def fight(self,other):
if(self.hp > 0):
print("%s did %d damage to %s"%(self.name,self.damage,other.name))
print("%s has %d hp left"%(other.name,other.hp))
other.hp -= self.damage
return other.fight(self) #Now the other pokemon fights back!
else:
print("%s wins! (%d hp left)"%(other.name,other.hp))
return other,self #return a tuple (winner,loser)
pikachu=Pokemon('pikachu', 100, 10)
pidgy=Pokemon('pidgy', 200, 12)
winner,loser = pidgy.fight(pikachu)
Of course, this is somewhat boring since the amount of damage does not depend on type of pokemon and isn't randomized in any way ... but hopefully it illustrates the point.
As for your class structure:
class Foo(object):
attr1=1
attr2=2
def __init__(self,attr1,attr2):
self.attr1 = attr1
self.attr2 = attr2
It doesn't really make sense (to me) to declare the class attributes if you're guaranteed to overwrite them in __init__. Just use instance attributes and you should be fine (i.e.):
class Foo(object):
def __init__(self,attr1,attr2):
self.attr1 = attr1
self.attr2 = attr2v
You don't need the variables up the top. You just need them in the init() method.
The fight method should return a value:
def fight(self, target):
target.nHealth -= self.nAttack
return target
You probably want to also check if someone has lost the battle:
def checkWin(myPoke, target):
# Return 1 if myPoke wins, 0 if target wins, -1 if no winner yet.
winner = -1
if myPoke.nHealth == 0:
winner = 0
elif target.nHealth == 0:
winner = 1
return winner
Hope I helped.
I am only going to comment on a few obvious aspects, because a complete code review is beyond the scope of this site (try codereview.stackexchange.com)
Your fight() method isn't saving the results of the subtraction, so nothing is changed. You would need to do something like this:
def fight(target, self):
target.nHealth -= self.nAttack
# check if target is dead now?
I might even recommend not imposing a modification on your target directly. It may be better if you can call an attack(power) on your target, and let it determine how much damage is done. You can then check if the target is dead yet. Ultimately I would think you would have some "dice" object that would determine the outcomes for you.
As for globals... just stop using them. It is a bad habit to have them unless you really have a good reason. Have functions that return results to the caller, which you then make use of:
def func(foo):
return 'bar'
You can however have a module of constants. These are a bunch of values that don't change for the life of the application. They are merely variables that provide common values. You might create a constants.py and have stuff like:
UP = "up"
DOWN = "down"
DEAD = 0
...
... And in your other modules you do:
from constants import *

Categories

Resources