Simple Pokemon battle

Simple Pokemon battle

From this application you can run a small pokemon battle based on stats of the pokemon. I created this application for the purpose of learning to use an API.

Pokemon API is one of well written and documented API so I started this project for fun and to learn how API's work

You can go through my project from my GitHub Repo

When I first started reading PokeAPI I was lost there were so many API's and each request is linked to another API. They are so many things but are perfectly balanced and working. I realized this was what good API looks and like and was disappointed for a bit for lack of my knowledge but I learned great things while reading all of these.

The Most important thing I learnt was we have to have a plan when going through an API, an clear objective on what I want and should be able to do. I spent an entire day wasting my time trying every request and trying to connect all the links. I took me 1 and half day to write a function just to fetch data from single type API. So I wrote down my objectives

  1. Make a class so that each we can individual instances for pokemons
  2. Add attack, defense features
  3. Attack and defense damage should be proportional to their stats

Going into the Project

I first created an class called Pokemon

class Pokemon:

    def __init__(self,name):
        self.name = name
        self.health = 1000

I created two instance variables so that each Pokemon has its own data. At first I gave name class instance the class input and health of 1000.

Next I want to get the Pokemon details if that instance so I wrote function for that

def get_pokemon_details(self):
    """About the function """
    ...

Remember docs strings are very important.

In order for me to write this function I should know before hand what will the request return to the API call(the API's will generally be "pokeapi.co/api/v2") so I used curL for that.

curL is amazing Linux command-line tool for transferring data using various network protocols. I used it to get data from API_URL

$ curl https://pokeapi.co/api/v2/<feature-name>

The output will be printed to the console. I highly recommend to learn curL

Once I figured out output format I wrote code to store all the request data to store in dictionary format

def get_pokemon_details(self):
        """This function will get all the details of given pokemon """

        pokemon = 'pokemon/' + str(self.name)
        poke_url = urljoin(URL,pokemon)
        poke_response = requests.get(url=poke_url).json()
        result = {
            'abilities' : [],
            'base_experience': poke_response['base_experience'],
            'height': poke_response['height'],
            'weight': poke_response['weight'],
            'forms' : [],
            'moves':[],
            'types':[],
            'stats' : {}

        }

but many keys have links to other API url's which I wont need so I used for loop to remove all the url's in the poke_response

for i in poke_response['abilities']:
            result['abilities'].append(i['ability']['name'])

        for j in poke_response['moves']:
            result['moves'].append(j['move']['name'])

        for k in poke_response['types'] :
            result['types'].append(k['type']['name'])

        for l in poke_response['stats']:
            # print(l['stat']['name'])
            result['stats'][str(l['stat']['name'])] = l['base_stat']

        for m in poke_response['forms']:
            result['forms'].append(m['name'])


        return result

then I wrote function for attacking since we got the pokemon details

    def attack(self,attack_name,defender_name):
        """This function will give damage to other pokemon that is mentioned """

        attack_stats  = self.get_pokemon_details()['stats']['attack']
        damage = self.damage_by_each_move(attack_name) * (attack_stats/2)
        print("damage given by {0} to {1} for         {2}".format(self.name,defender_name.name,damage))
        try:
            def_damage = defender_name.damage_taken(damage)

        except:
            raise KeyError("check defender name")

the self.damage_given_by_each_move() is other function which will check if the given attack is there for the pokemon and returns how much damage it will make if you want to code you can go to my GitHub repo mentioned at top

the attack also based on attack stat of pokemon this function will fetch the attack stat from pokemon details and multiply it to damage of move

Then I written function for how much damage should the pokemon should take for the attack by an opponent

    def damage_taken(self,damage):
        """This function will decrease the health of the pokemon based
            on the damage given by an other pokemon.
            The damage taken will also based on the defense stat of this
            pokemon other than attack power of opponent

        """
        stat_defense = self.get_pokemon_details()['stats']['defense']

        # real damage will be reduced according to defense stat of pokemon
        real_damage = damage / (stat_defense/10)
        self.health -= real_damage
        print("{0}'s health = {1}".format(self.name,self.health))

As you can see the damage taken will also be proportional to the defense stat in pokemon details.

So now we have established how much damage will be given and taken I wrote a function for battlefield

def battle_arena():
    """ 
    This function is battlefield for two pokemons they battle it out
    by mentioning attacks and opponents and whose health gets below
    their stats hp they loose

    After executing the function you will be prompted to type the pokemon
    names and then you should enter your attack name each time until ones health 
    is below their hp then battle state will be changed to stop and 
    while loop stops

    """

    c1_name = input("Contender 1 enter your pokemon name:")
    contender_1 = Pokemon(c1_name)

    c2_name = input("Contender 2 enter your pokemon name:")
    contender_2 = Pokemon(c2_name)

    battle_state = "start"


    while battle_state == 'start':

        print('Contender 1 its your turn.')
        attack_name = input("Enter your attack:")
        contender_1.attack(attack_name,contender_2)

        print('Contender 2 its your turn')
        c2_attack_name = input("Enter your attacj:")
        contender_2.attack(c2_attack_name,contender_1)


        c1_hp = contender_1.get_pokemon_details()['stats']['defense'] * 10
        c2_hp = contender_2.get_pokemon_details()['stats']['defense'] * 10
        if contender_1.health <= c1_hp:
            print("{0} is dead. Contender 2 is winner".format(contender_1.name))
            battle_state = "stop"
        elif contender_2.health <= c2_hp:
            print("{0} is dead. Contender 1 is winner".format(contender_2.name))
            battle_state = "stop"

First it would ask for you enter the pokemon name contender 1 is choosing and if the name is valid it will ask second contender to choose pokemon name

Then both instances of the pokemon are created and it will prompt you to give attack name you want to use and then it will print out damage done to opponent pokemon

(pokemon) test@test:~/pokemon$ python3 run.py
Contender 1 enter your pokemon name:pikachu
pikachu
Contender 2 enter your pokemon name:bulbasaur
bulbasaur
Contender 1 its your turn.
Enter your attack:thunder-shock
damage given by pikachu to bulbasaur for 1100.0
bulbasaur's health = 9775.51
Contender 2 its your turn
Enter your attack:energy-ball
damage given by bulbasaur to pikachu for 2205.0
pikachu's health = 9448.75
Contender 1 its your turn.
Enter your attack:

similarly it will be done for the opposite side as shown above. This will continue until one of the pokemon health drops below number proportional to hp stat mentioned in the pokemon details.

Testing

I learned how to test requests through his project. I used responses for this project.

I can mock requests object response using the responses library with ease you can go through above link on how to do it .

import requests
import responses

@responses.activate
def test_pokemon_attack():

    poke_name = Pokemon('pikachu')
    responses.add(responses.GET,'https://pokeapi.co/api/v2/pokemon/pikachu',json=FAKE_POKEMON_RESPONSE)
    assert_value = poke_name.get_pokemon_details()['types']
    output = ['electric']

    assert assert_value == output

json=FAKE_PYTHON_RESPONSE is the one that you are mocking the output with.

If you have come this far reading the article I hope you liked it and if there are any issues with code the please create a issue at my GitHub repo Link: github.com/filius-fall/pokemon_api