loading...

Daily Challenge #170 - Pokemon Damage Calculator

thepracticaldev profile image dev.to staff ・1 min read

Setup

For this challenge, you'll be thrown into a Pokemon battle! Calculate the damage that a particular move would do using the following formula:

total damage = base damage * (attack / defense) * effectiveness

base damage = the original power of the attack
attack = your attack stat
defense = the opponent's defense stat
effectiveness = the effectiveness of the attack based on the type matchup

Attacks can be super effective, neutral, or not very effective depending on the matchup.

  • super effective : 2x damage
  • neutral: 1x damage
  • not very effective: 0.5x damage

To prevent the challenge from being too tedious, you'll only deal with four types: fire, water, grass, and electric. Here are the matchups:

fire > grass
fire < water
fire = electric
water < grass
water < electric
grass = electric
**Any type against itself is not very effective

Overall, the function you implement must take in:

  • your type
  • the opponent's type
  • attack power
  • the opponent's defense

... and must output the total damage of the attack.

Tests

What are the total damage outputs of these attacks?

  1. "grass", "electric", 57, 19
  2. "grass", "water", 40, 40
  3. "grass", "fire", 35, 5
  4. "fire", "electric", 10, 2

Good luck!


This challenge comes from yaphi1 on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Posted on by:

thepracticaldev profile

dev.to staff

@thepracticaldev

The hardworking team behind dev.to ❤️

Discussion

pic
Editor guide
 

As there's no mention of the value, I set the base damage to 50 in each scenario.

Code

def compare_attack_types(first_type, second_type):
    if first_type == "fire":
        if second_type == "grass":
            return 2
        if second_type == "water":
            return 0.5
    if first_type == "grass":
        if second_type == "fire":
            return 0.5
        if second_type == "water":
            return 2
    if first_type == "electric":
        if second_type == "water":
            return 2
    if first_type == "water":
        if second_type == "fire":
            return 2
        if second_type == "grass":
            return 0.5
    return 1

def calculate_damage(base_damage, own_type, opponent_type, attack, defense):
    return base_damage * (attack / defense) * compare_attack_types(own_type, opponent_type)

print(calculate_damage(50, "grass", "electric", 57, 19))
print(calculate_damage(50, "grass", "water", 40, 40))
print(calculate_damage(50, "grass", "fire", 35, 5))
print(calculate_damage(50, "fire", "electric", 10, 2))

Results

150
100
175
250

 

Ok cool. I'll use 50, too.

Here'a another Python implementation:

SUPER_EFFECTIVE = 'super_effective'
NEUTRAL = 'neutral'
NOT_VERY_EFFECTIVE = 'not_very_effective'

EFFECTIVENESS_MULTIPLIER = {
  SUPER_EFFECTIVE: 2,
  NEUTRAL: 1,
  NOT_VERY_EFFECTIVE: .5}

FIRE = 'fire'
GRASS = 'grass'
WATER = 'water'
ELECTRIC = 'electric'

ATTACK_ON_DEFENSE_EFFECTIVENESS = {
  FIRE: {
    FIRE: NOT_VERY_EFFECTIVE,
    GRASS: SUPER_EFFECTIVE,
    WATER: NOT_VERY_EFFECTIVE,
    ELECTRIC: NEUTRAL,
  },
  GRASS: {
    GRASS: NOT_VERY_EFFECTIVE,
    WATER: SUPER_EFFECTIVE,
    ELECTRIC: NEUTRAL,
    FIRE: NOT_VERY_EFFECTIVE
  },
  WATER: {
    WATER: NOT_VERY_EFFECTIVE,
    GRASS: NOT_VERY_EFFECTIVE,
    ELECTRIC: NOT_VERY_EFFECTIVE,
    FIRE: SUPER_EFFECTIVE
  },
  ELECTRIC: {
    ELECTRIC: NOT_VERY_EFFECTIVE,
    GRASS: NEUTRAL,
    WATER: SUPER_EFFECTIVE,
    FIRE: SUPER_EFFECTIVE
  }
}

def _calculate_effectiveness(attack_type, defense_type):
  effectiveness_name = ATTACK_ON_DEFENSE_EFFECTIVENESS[attack_type][defense_type]
  return EFFECTIVENESS_MULTIPLIER[effectiveness_name]

def _total_damage(base_damage, attack, defense, effectiveness):
  return base_damage * (attack / defense) * effectiveness

def calculate_damage(base_damage, attack_type, defense_type, attack_power, defense_power):
  return _total_damage(
    base_damage,
    attack_power,
    defense_power,
    _calculate_effectiveness(attack_type, defense_type)
  )

print(calculate_damage(50, "grass", "electric", 57, 19))
print(calculate_damage(50, "grass", "water", 40, 40))
print(calculate_damage(50, "grass", "fire", 35, 5))
print(calculate_damage(50, "fire", "electric", 10, 2))

 

PHP ::)

class Pokemon {

    public $baseDamage;
    public $own;
    public $opponent;
    public $attack;
    public $defense;

    public function __construct ($baseDamage, $own, $opponent, $attack, $defense)
    {
        $this->baseDamage = $baseDamage;
        $this->attack = $attack;
        $this->defense = $defense;
        $this->own = $own;
        $this->opponent = $opponent;
    }

    public function compareAttackTypes ()
    {
        switch($this->own){
            case "fire":
                if($this->opponent == "grass"){ return 2; }
                if($this->opponent == "water"){ return 0.5; }
            case "grass":
                if($this->opponent == "fire"){ return 0.5; }
                if($this->opponent == "water"){ return 2; }
            case "electric":
                if($this->opponent == "water"){ return 2; }
            case "water":
                if($this->opponent == "fire"){ return 2; }
                if($this->opponent == "grass"){ return 0.5; }
            default:
                return 1;
        }
    }

    public function calculateDamage ()
    {
        return $this->baseDamage * ($this->attack / $this->defense) * $this->compareAttackTypes();
    }
}

$pk = new Pokemon(50, "grass", "water", 40, 40); // result : 100
echo $pk->calculateDamage();
 

Haskell solution. The last argument of the function is the base damage. I'm also changing the function to accept an ADT Type type instead of strings for the Pokémon type.

data Type = Grass | Fire | Water | Electric deriving (Eq)

effect :: Type -> Type -> Double
effect Fire Grass = 2
effect Water Fire = 2
effect Fire Electric = 1
effect Grass Water = 2
effect Electric Water = 2
effect Grass Electric = 1
effect a b
  | a == b    = 1
  | otherwise = recip $ effect b a

totalDamage :: Type -> Type -> Double -> Double -> Double -> Double
totalDamage t1 t2 att def = (*) $ att / def * effect t1 t2
 

Pattern matching for the win!

I didn't know what to do with the base_power thing, so I left it as one.

Elixir

defmodule Pokemon do
  def calculate(effectiveness, attack, defence) do
    1 * (attack / defence) * effectiveness
  end

  def total_damage(a, a, att, def), do: calculate(0.5, att, def)
  def total_damage("electric", "water", att, def), do: calculate(2, att, def)
  def total_damage("fire", "grass", att, def), do: calculate(2, att, def)
  def total_damage("fire", "water", att, def), do: calculate(0.5, att, def)
  def total_damage("grass", "fire", att, def), do: calculate(0.5, att, def)
  def total_damage("grass", "water", att, def), do: calculate(2, att, def)
  def total_damage("water", "electric", att, def), do: calculate(0.5, att, def)
  def total_damage("water", "fire", att, def), do: calculate(2, att, def)
  def total_damage("water", "grass", att, def), do: calculate(0.5, att, def)
  def total_damage(_, _, att, def), do: calculate(1, att, def)
end