Powered by AppSignal & Oban Pro
Would you like to see your link here? Contact us

Pokemon Battle

exercises/pokemon_battle.livemd

Pokemon Battle

Mix.install([
  {:jason, "~> 1.4"},
  {:kino, "~> 0.9", override: true},
  {:youtube, github: "brooklinjazz/youtube"},
  {:hidden_cell, github: "brooklinjazz/hidden_cell"}
])

Navigation

Home Report An Issue RPG DialogueRanges

Overview

You’re going to create a pokemon battle game. If you’re not familiar with pokemon, it’s a game where elemental creatures battle.

Define The Pokemon Struct

You’re going to represent pokemon using a Pokemon struct with the following keys.

  • :name will be a string.
  • :type will be an atom of either :grass, :water, or :fire
  • :health will be a float with a default value of 20.0
  • :attack will be an integer with a default value of 5
  • :speed will be an integer

You do not need to validate the data types for the keys above. These are simply the expected data types for each Pokemon struct instance.

%Pokemon{name: "Bulbasaur", type: :grass, health: 20, attack: 5, speed: 20}

Pokemon.attack/2

Create a Pokemon.attack/2 function to make one pokemon attack another.

The pokemon will apply their :attack value multiplied by a type advantage modified according to the following list. strong attacks are multiplied by 2 and weak attacks are multiplied by 0.5.

  • :fire is strong against :grass
  • :grass is strong against :water
  • :water is strong against :fire
  • :fire is weak against :water
  • :grass is weak against :fire
  • :water is weak against :grass
  • the same type should deal normal damage.

For example:

attacker = %Pokemon{name: "Charmander", type: :fire, health: 20.0, attack: 5, speed: 20}
defender = %Pokemon{name: "Bulbasaur", type: :grass, health: 20.0, attack: 5, speed: 20}

# Applies 5 * 2 Damage. Original Health: 20.0, New Health: 10.0.
Pokemon.attack(attacker, defender)
%Pokemon{name: "Bulbasaur", type: :grass, health: 10.0, attack: 5, speed: 20}

Example solution

defmodule Pokemon do
  defstruct [:name, :type, :health, :attack, :speed]

  def attack(attacker, defender) do
    damage = attacker.attack * modifier(attacker.type, defender.type)
    %__MODULE__{defender | health: defender.health - damage}
  end

  defp modifier(attacker_type, defender_type) do
    cond do
      super_effective?(attacker_type, defender_type) -> 2
      super_effective?(defender_type, attacker_type) -> 0.5
      true -> 1
    end
  end

  defp super_effective?(attacker_type, defender_type) do
    {attacker_type, defender_type} in [{:fire, :grass}, {:grass, :water}, {:water, :fire}]
  end
end
defmodule Pokemon do
  @moduledoc """
  Pokemon

  ## Examples
      iex> attacker = %Pokemon{name: "Charmander", type: :fire, health: 20.0, attack: 5, speed: 20}
      iex> defender = %Pokemon{name: "Bulbasaur", type: :grass, health: 20.0, attack: 5, speed: 20}
      iex> Pokemon.attack(attacker, defender)
      %Pokemon{name: "Bulbasaur", type: :grass, health: 10.0, attack: 5, speed: 20}
  """
  
  defstruct [:name, :attack, :health, :speed, :type]

  def attack(attacker, defender) do
    dmg = attacker.attack * modifier(attacker.type, defender.type)
    %__MODULE__{defender | health: defender.health - dmg}
  end

  defp modifier(attacker, defender) do
    cond do
      strong_attack?(attacker, defender) -> 2
      strong_attack?(defender, attacker) -> 0.5
      true -> 1
    end
  end

  defp strong_attack?(attacker, defender) do
    {attacker, defender} in [{:fire, :grass}, {:grass, :water}, {:water, :fire}]
  end
end

Consider using the following Elixir cell to test your solution.

charmander = %Pokemon{name: "Charmander", type: :fire, health: 20.0, attack: 5, speed: 20}
bulbasaur = %Pokemon{name: "Bulbasaur", type: :grass, health: 20.0, attack: 5, speed: 20}
squirtle = %Pokemon{name: "Squirtle", type: :water, health: 20.0, attack: 5, speed: 20}
bulbasaur = Pokemon.attack(squirtle, bulbasaur)
squirtle = Pokemon.attack(bulbasaur, squirtle)
squirtle = Pokemon.attack(bulbasaur, squirtle)

Pokemon Instances

Bind three variables charmander, bulbasaur, and squirtle to an instance of a Pokemon struct with the following information.

classDiagram
  class charmander {
    name: "Charmander"
    type: :fire
    health: 20.0
    attack: 5
    speed: 20
  }
  class bulbasaur {
    name: "Bulbasar"
    type: :grass
    health: 20.0
    attack: 5
    speed: 20
  }
  class squirtle {
    name: "Squirtle"
    type: :water
    health: 20.0
    attack: 5
    speed: 20
  }

You may use these three structs to test your Pokemon.attack/2 function.

Example solution

charmander = %Pokemon{name: "Charmander", type: :fire, health: 20, attack: 5, speed: 20}
bulbasaur = %Pokemon{name: "Bulbasaur", type: :grass, health: 20, attack: 5, speed: 20}
squirtle = %Pokemon{name: "Squirtle", type: :water, health: 20, attack: 5, speed: 20}

# Testing Example
Pokemon.attack(charmander, bulbasaur)

Enter your solution below.

charmander = %Pokemon{name: "Charmander", type: :fire, health: 20.0, attack: 5, speed: 20}
bulbasaur = %Pokemon{name: "Bulbasaur", type: :grass, health: 20.0, attack: 5, speed: 20}
squirtle = %Pokemon{name: "Squirtle", type: :water, health: 20.0, attack: 5, speed: 20}

Commit Your Progress

DockYard Academy now recommends you use the latest Release rather than forking or cloning our repository.

Run git status to ensure there are no undesirable changes. Then run the following in your command line from the curriculum folder to commit your progress.

$ git add .
$ git commit -m "finish Pokemon Battle exercise"
$ git push

We’re proud to offer our open-source curriculum free of charge for anyone to learn from at their own pace.

We also offer a paid course where you can learn from an instructor alongside a cohort of your peers. We will accept applications for the June-August 2023 cohort soon.

Navigation

Home Report An Issue RPG DialogueRanges