2

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?

Web Owl
  • 567
  • 2
  • 15
  • 29
  • What is your specific question here? If you are asking why your `fight` method isn't working, its because you aren't saving the results of the subtraction. – jdi Jul 29 '12 at 04:02
  • My question is pretty how, how should this look for it to work correctly. But yeah, how would I pass the results? return? – Web Owl Jul 29 '12 at 04:03
  • I'm not really sure how to answer this, because its more like a broad code review. You should try asking for a code review here: http://codereview.stackexchange.com/ ... But yes you should not being making such heavy use of globals. Operations should return results to the callers. – jdi Jul 29 '12 at 04:06
  • Thanks. But to narrow down the question, how would I return the value correctly and am I using class correctly? Also, where can I put these variables so they are not shoved at the top? – Web Owl Jul 29 '12 at 04:09

3 Answers3

3

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
mgilson
  • 300,191
  • 65
  • 633
  • 696
  • Thanks, you have really helped to make this clearer for me. For now the simple battle is just what I need to know, later down the road I am going to add types, damage muliplyers, moves, the whole pokemon thing. I need to start using game states and a whole load of classes. I should also use multiple files before this single page doesn't get over crowded. A start menu... so much to do lol. Thank again! Really appreciate the help. – Web Owl Jul 29 '12 at 04:22
2
  1. You don't need the variables up the top. You just need them in the init() method.
  2. The fight method should return a value:

    def fight(self, target): 
        target.nHealth -= self.nAttack
        return target
    
  3. 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.

mattjegan
  • 2,724
  • 1
  • 26
  • 37
  • Gah you beat me to it. I might suggest though that the return isn't necessary in `fight`. The caller obviously knows the target because its the parameter – jdi Jul 29 '12 at 04:09
  • I'll be more than happy to show it when it is done, this is just a task I gave myself to help learn it. I am not even sure how far I'll get, but my goal is to play out the game as a mud text adventure. – Web Owl Jul 29 '12 at 04:16
2

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 *
Community
  • 1
  • 1
jdi
  • 90,542
  • 19
  • 167
  • 203
  • yeah I should put them in functions and stop globally demanding them. If I keep doing that I'll have a huge mess to clean up later. Thanks – Web Owl Jul 29 '12 at 04:15