Powered by AppSignal & Oban Pro

Pokemon Battle

exercises/pokemon_battle.livemd

Pokemon Battle

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

Navigation

Return Home Report An Issue

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.

You’re going to represent pokemon using a Pokemon struct with the keys :name, :type, :health, :attack, and :speed. Enforce that all keys must have a value.

  • :name is a string.
  • :type will be an atom of either :grass, :water, or :fire
  • :health will be an integer with a default value of 20
  • :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}

Then implement the Pokemon.attack/2 function according to the documented examples.

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

Pokemon.attack(attacker, defender)
# output: subtract attack from health to return an updated pokemon struct
%Pokemon{name: "Bulbasaur", type: :grass, health: 15, attack: 5, speed: 20}

Pokemon.attack/2 should apply double damage if the pokemon has a type advantage, and half damage if the pokemon has a type disadvantage.

The advantages are:

  • :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.
attacker = %Pokemon{name: "Charmander", type: :fire, health: 20, attack: 5, speed: 20}
defender = %Pokemon{name: "Bulbasaur", type: :grass, health: 20, attack: 5, speed: 20}

Pokemon.attack(attacker, defender)
# output: subtract attack (doubled) from health to return an updated pokemon struct
%Pokemon{name: "Bulbasaur", type: :grass, health: 10, attack: 5, speed: 20}
defmodule Pokemon do
  @moduledoc """
  Pokemon

  ## Examples

    iex> %Pokemon{name: "Charmander", type: :fire, health: 20, attack: 5, speed: 20}
    %Pokemon{name: "Charmander", type: :fire, health: 20, attack: 5, speed: 20}

    iex> %Pokemon{name: "Charmander", type: :fire, speed: 20}
    %Pokemon{name: "Charmander", type: :fire, health: 20, attack: 5, speed: 20}
  """

  @doc """
  subtract the attack damage of an attacker from the defender's health.
  return an updated pokemon struct, and take type advantage into consideration.

  ## Examples

    Same Type

    iex> attacker = %Pokemon{name: "Charmander", type: :fire, health: 20, attack: 5, speed: 20}
    iex> defender = %Pokemon{name: "Charmander", type: :fire, health: 20, attack: 5, speed: 20}
    iex> Pokemon.attack(attacker, defender)
    %Pokemon{name: "Charmander", type: :fire, health: 15, attack: 5, speed: 20}

    Type Disadvantage

    iex> attacker = %Pokemon{name: "Bulbasaur", type: :grass, health: 20, attack: 5, speed: 20}
    iex> defender = %Pokemon{name: "Charmander", type: :fire, health: 20, attack: 5, speed: 20}
    iex> Pokemon.attack(attacker, defender)
    %Pokemon{name: "Charmander", type: :fire, health: 17.5, attack: 5, speed: 20}

    Type Advantage

    iex> attacker = %Pokemon{name: "Charmander", type: :fire, health: 20, attack: 5, speed: 20}
    iex> defender = %Pokemon{name: "Bulbasaur", type: :grass, health: 20, attack: 5, speed: 20}
    iex> Pokemon.attack(attacker, defender)
    %Pokemon{name: "Bulbasaur", type: :grass, health: 10, attack: 5, speed: 20}
  """
  def attack(attacker, defender) do
  end
end

Consider using the following Elixir cell to test your solution.

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
    attack: 5
    speed: 20
  }
  class bulbasaur {
    name: "Bulbasar"
    type: :grass
    health: 20
    attack: 5
    speed: 20
  }
  class squirtle {
    name: "Squirtle"
    type: :water
    health: 20
    attack: 5
    speed: 20
  }

Use may 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.

Mark As Completed

file_name = Path.basename(Regex.replace(~r/#.+/, __ENV__.file, ""), ".livemd")

save_name =
  case Path.basename(__DIR__) do
    "reading" -> "pokemon_battle_reading"
    "exercises" -> "pokemon_battle_exercise"
  end

progress_path = __DIR__ <> "/../progress.json"
existing_progress = File.read!(progress_path) |> Jason.decode!()

default = Map.get(existing_progress, save_name, false)

form =
  Kino.Control.form(
    [
      completed: input = Kino.Input.checkbox("Mark As Completed", default: default)
    ],
    report_changes: true
  )

Task.async(fn ->
  for %{data: %{completed: completed}} <- Kino.Control.stream(form) do
    File.write!(
      progress_path,
      Jason.encode!(Map.put(existing_progress, save_name, completed), pretty: true)
    )
  end
end)

form

Commit Your Progress

Run the following in your command line from the curriculum folder to track and save your progress in a Git commit. Ensure that you do not already have undesired or unrelated changes by running git status or by checking the source control tab in Visual Studio Code.

$ git checkout -b pokemon-battle-exercise
$ git add .
$ git commit -m "finish pokemon battle exercise"
$ git push origin pokemon-battle-exercise

Create a pull request from your pokemon-battle-exercise branch to your solutions branch. Please do not create a pull request to the DockYard Academy repository as this will spam our PR tracker.

DockYard Academy Students Only:

Notify your teacher by including @BrooklinJazz in your PR description to get feedback. You (or your teacher) may merge your PR into your solutions branch after review.

If you are interested in joining the next academy cohort, sign up here to receive more news when it is available.

Up Next

Previous Next
RPG Dialogue Ranges