Become a Pokemon Master Challenge Project (Python)

I need more coffee. I forgot I refactored the constructor and forgot to update those objects down below. Thank you for spotting that! :slight_smile:

1 Like

Just playing around with this. I added the first 10 Pokemon from the Gen 6 deck and all the elements, then made a battle royale where round after round each pokemon attacks a random target in random order until there’s only one remaining.

Gonna start work on adding trainer class later. Fun times.

Still have a couple functions to add.

https://github.com/HTH24/Pokemon-Game/blob/master/Pokemon_Project.py

How can i set “is_knocked_out” =True, without calling any method on my instance, i think that my code should know automatically when the health of pokemon has become zero and automatically change its attribute is_knocked_out to True,
I searched online but didn’t find any definitive solution
Can someone please explain me how to do this, because i think i might have hit a wall here.

The easy answer should be

class Pokeman
    def __init__(self, name, current_health = 50, is_knocked_out = False)
      self.is_knocked_out = is_knocked_out
      self.current_health = current_health
      self.name = name
  
pikachu = Pokemon("Pikachu")
if pikachu.current_health <= 0:
    pikachu.is_knocked_out = True

It’s hard to understand without seeing your code, however I suggest creating a knockout method in your class. Here is how I did it:

def knockout(self):
    print("{} has been knocked out!".format(self.name))
    self.is_knocked_out = True

Then

if pikachu.current_health <= 0:
  pikachu.knockout()

Or create separate method for losing health which calls the knockout method when health fall below zero:

def lose_health(self, hit):
    self.current_health -= hit
    print("{} loses {} health".format(self.name, hit))
    if self.current_health <= 0:
        self.current_health = 0
        self.knockout()
    else:
        print("{}'s current health is {}".format(self.name, self.current_health))

Hope this helps

Thanks @caseygobrien this definitely helps :slight_smile:

1 Like

Just a bit of fun halfway through this one :slight_smile:Lettuce

Perhaps a silly questions, but was the download for this supposed to be an empty file? The wording of the project seems to imply that items are already written.

1 Like

This is exactly what I came to ask! The instructions for this whole project seem to be constantly referring to some previously-completed project that I’ve never seen. :unamused:

1 Like

Really enjoyed that challenge, and it’s given me a lot more confidence, particularly with classes.

Here’s my effort:

Haven’t put that much work into it but had some fun!

Hope anyone can get some inspo from what I’ve done :smiley:

Hi everyone, this is my first project and I wanted to share it with you :slight_smile:

1 Like

class Pokemon:
def init (self, name, level, type, max_health, health, is_knocked_out):
self.name = name
self.level = level
self.type = type
self.max_health = max_health
self.health = health
self.is_knocked_out = is_knocked_out

def lose_health (self, health_change):
    self.health = self.health - health_change
    if self.health <= 0:
        self.health = 0
        print("{} is knocked out.".format(self.name))
        self.is_knocked_out = True
        
def gain_health (self, health_change):
    self.health = self.health + health_change
    if self.health > self.max_health:
        self.health = self.max_health
    if self.health > 0:
        self.is_knocked_out = False
    print("{} now has {} health.".format(self.name,self.health))
    
def attack (self, other_pokemon):
    damage = 0
    if self.type == "Fire" and other_pokemon.type == "Fire":
        damage = 0.5 * self.level
    elif self.type == "Fire" and other_pokemon.type == "Water":
         damage = 0.5 * self.level
    elif self.type == "Fire" and other_pokemon.type == "Grass":
        damage = 2 * self.level
    elif self.type == "Water" and other_pokemon.type == "Fire":
        damage = 2 * self.level
    elif self.type == "Water" and other_pokemon.type == "Water":
        damage = 0.5 * self.level
    elif self.type == "Water" and other_pokemon.type == "Grass":
        damage = 0.5 * self.level
    elif self.type == "Grass" and other_pokemon.type == "Fire":
        damage = 0.5 * self.level
    elif self.type == "Grass" and other_pokemon.type == "Water":
        damage = 2 * self.level
    else:
        damage = 0.5 * self.level            
    
    print("{} has attacked {} and caused {} points of damage.".format(self.name, other_pokemon.name,damage))
    Pokemon.lose_health(other_pokemon,damage)
    print("{}'s health is now {}.".format(other_pokemon.name, other_pokemon.health))

class Trainer (Pokemon):
def init (self, name, pokemons, current_pokemon, potions):
self.name = name
self.pokemons = pokemons
self.current_pokemon = current_pokemon
self.potions = potions
len(pokemons) <= 6

def use_potion (self, potion):
    Pokemon.gain_health(self.current_pokemon,self.potions[potion])   
    
def attack_other_trainer (self, other_trainer):
    if self.current_pokemon.is_knocked_out == False:
        Pokemon.attack(self.current_pokemon,other_trainer.current_pokemon)
    else:
        print("{} is knocked out and cannot attack.".format(self.current_pokemon.name))
    
def change_current_pokemon (self, new_pokemon):
    if new_pokemon in self.pokemons and new_pokemon != self.current_pokemon:
        self.current_pokemon = new_pokemon
        print("Current pokemon is now {}.".format(self.current_pokemon.name))
    elif self.current_pokemon.is_knocked_out:
        print("You cannot change to a pokemon that is knocked out.  Try again.")
    else:
        print("This change is not allowed. Try again.")

This isn’t the prettiest code, but it works! I think I’m finally starting to understand classes.

I wanted to prevent instances of the Trainer class from having duplicate names. So I created a global Trainers list which would be populated as new Trainer instances are created.

Then in the Trainer __init__ method, I tried to test the incoming name against all the instances in the Trainer list. If the name already exists in the list, I tried raising an error.

Unfortunately, that did not prevent a malformed Trainer from being created.

So if the name is used already, I create a trainer named ‘bad_trainer_prepare_to_destroy’. Next I implemented the __del__ dunder method.

I tried calling __del__ within the __init__ method for the case of bad input data. That didn’t work.

I tried calling it from within the __repr__ dunder method for the bad trainer: self.__del__()

Unfortunately it destroyed ALL of my Trainer class instances.

My guess is there is a more or less standard way to prevent instantiating a class with incorrect values such as a duplicate trainer name. But after quite a bit of googling, I haven’t found it yet. Any ideas for me for this type of coding problem?

Thanks in advance!

Here is the relevant code from my Trainer class:

class Trainer():
    # pokemons is a list of Pokemon instances. 
    # potions is a list of keys to the potions dictionary.
    # current pokemon is the index in list of pokemons
    def __init__(self, name, pokemons, potions, current_pokemon):
        try:
            if name not in trainers:
                self.name = name
                self.pokemons = pokemons
                self.potions = potions
                self.current_pokemon = current_pokemon

                trainers.append(self.name)
            else:
                self.name = 'bad_trainer_prep_for_destruction'
                self.pokemons = []
                self.potions = []
                self.current_pokemon = -1
                raise ValueError
        except ValueError:
            print("OOPS! Trainer name {name} already taken.".format(name = name))
            # unfortunately, while this raises an error, a broken class is still instantiated. Can we manage it via __del__ ?

    # at least in my tests, the __del__ dunder method destroys ALL instances of the class, even if i call it for the current instance (from inside then __repr__ when the class instance got set up incorrectly). How do i just destroy the current instance?

    def __del__(self):
      instance_name = self.name       
      print(instance_name, "destroyed")

    def __repr__(self):
        if self.name != 'bad_trainer_prep_for_destruction':
            trainer = self.name
            poke_names = self.pokemons[0].name if len(self.pokemons) > 0 else 'NONE!'

            potion_names = ', '.join(self.potions)

            active_poke = self.pokemons[self.current_pokemon].name if len(self.pokemons) > 0 else 'NONE!'

            for poke in self.pokemons:
                curr_name = poke.name
                if poke_names.find(curr_name) == -1:
                    poke_names = poke_names + ', ' + curr_name

            return "Trainer {name} is ready to go!\n{name}'s pokemons include: {pokemons}.\nAvailable healing potions are {potions}.\nActive pokemon is {active}.\n".format(name=Fore.BLUE + trainer + Style.RESET_ALL, pokemons=Fore.MAGENTA + poke_names + Style.RESET_ALL, potions=Fore.GREEN + potion_names + Style.RESET_ALL,active=Fore.RED + active_poke + Style.RESET_ALL)
        else:
            self.__del__()
            return

And here we build some trainers, including one with a duplicate name:

# Build some trainers

ash = Trainer('Ash',[charmander, bulbasaur, charizard, wartortle], ['firewater', 'grasstea', 'nutstew', 'seaweed', 'chocolate'],0)

print(ash)

serena = Trainer('Serena',[squirtle, venusaur, charmeleon, blastoise], ['firewater', 'grasstea', 'nutstew', 'seaweed', 'chocolate'],0)

print(serena)

test that trainer names cannot be duplicated:

test = Trainer('Ash',[], ['firewater', 'grasstea', 'nutstew', 'seaweed', 'chocolate'],0)

print(test)

And here are results:

Trainer Ash is ready to go!
Ash's pokemons include: Charmander, Bulbasaur, Charizard, Wartortle.
Available healing potions are firewater, grasstea, nutstew, seaweed, chocolate.
Active pokemon is Charmander.

Trainer Serena is ready to go!
Serena's pokemons include: Squirtle, Venusaur, Charmeleon, Blastoise.
Available healing potions are firewater, grasstea, nutstew, seaweed, chocolate.
Active pokemon is Squirtle.

OOPS! Trainer name Ash already taken.
bad_trainer_prep_for_destruction destroyed
Traceback (most recent call last):
  File "/Users/kevinoh/Workspace/scratchpad/pokemon_starting/pokemon.py", line 197, in <module>
    print(test)
TypeError: __str__ returned non-string (type NoneType)
Ash destroyed
Serena destroyed
bad_trainer_prep_for_destruction destroyed