Pokemon Battle
Mix.install([
{:kino, github: "livebook-dev/kino", override: true},
{:kino_lab, "~> 0.1.0-dev", github: "jonatanklosko/kino_lab"},
{:vega_lite, "~> 0.1.4"},
{:kino_vega_lite, "~> 0.1.1"},
{:benchee, "~> 0.1"},
{:ecto, "~> 3.7"},
{:math, "~> 0.7.0"},
{:faker, "~> 0.17.0"},
{:utils, path: "#{__DIR__}/../utils"},
{:tested_cell, git: "https://github.com/BrooklinJazz/tested_cell"}
])
Navigation
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.
In this game, you’re going to create a few pokemon, charmander
, squirtle
, and bulbasaur
then have them battle.
Some Elixir cells in this exercise will rely on previous solutions, so ensure that you
use the ea
command to evaluate all cells. Otherwise, your prior code may be stale and result in bugs.
Define A Pokemon Struct
In the Elixir cell below, define a Pokemon
struct with the keys :name
, :type
, health
, :attack
, and :speed
.
-
:name
will be a string. -
:type
will be an atom of either:grass
,:water
, or:fire
-
:health
will be an integer with a default value of20
-
:attack
will be an integer with a default value of5
-
:speed
will be an integer
ExUnit.start(auto_run: false)
defmodule Assertion do
use ExUnit.Case
test "" do
defmodule Pokemon do
end
assert Keyword.get(Pokemon.__info__(:functions), :__struct__),
"Ensure you use `defstruct`."
assert match?(%{name: nil, type: nil, speed: nil}, struct(Pokemon)),
"Ensure you use `defstruct` with :name, :type, :health, :attack, and :speed."
assert match?(%{health: 20, attack: 5}, struct(Pokemon)),
"Ensure :health has a default value of 20 and :attack has a default value of 5."
end
end
ExUnit.run()
# Make variables and modules defined in the test available.
# Also allows for exploration using the output of the cell.
defmodule Pokemon do
end
Create 3 Pokemon
In the Elixir cell below, create 3 variables charmander
, bulbasaur
, and squirtle
.
Bind each variable to a Pokemon
struct with the following stats.
classDiagram
class Charmander {
type: :fire
speed: 20
}
class Bulbasaur {
type: :grass
speed: 15
}
class Squirtle {
type: :water
speed: 10
}
Replace nil
with your solution.
ExUnit.start(auto_run: false)
defmodule Assertion do
use ExUnit.Case
test "" do
charmander = nil
bulbasaur = nil
squirtle = nil
assert is_struct(charmander), "Ensure `charmander` is a struct."
assert is_struct(squirtle), "Ensure `squirtle` is a struct."
assert is_struct(bulbasaur), "Ensure `bulbasaur` is a struct."
assert %Pokemon{name: "Charmander", type: :fire, attack: 5, health: 20, speed: 20} =
charmander
assert %Pokemon{name: "Bulbasaur", type: :grass, attack: 5, health: 20, speed: 15} = bulbasaur
assert %Pokemon{name: "Squirtle", type: :water, attack: 5, health: 20, speed: 10} = squirtle
end
end
ExUnit.run()
# Make variables and modules defined in the test available.
# Also allows for exploration using the output of the cell.
charmander = nil
bulbasaur = nil
squirtle = nil
Pokemon Battle
Create a PokemonBattle
module with the following functions:
attack/2
Create an attack/2
function which:
- accepts two pokemon structs as parameters.
- return an updated version of the second pokemon struct.
- subtract the first pokemon’s attack from the second pokemon’s health.
- double the damage dealt if the pokemon has a type advantage.
- half the damage dealt if the pokemon has a type weakness.
For example,
squirtle = %Pokemon{name: "Squirtle", type: :water, attack: 10}
charmander = %Pokemon{name: "Charmander", type: :fire, health: 20}
PokemonBattle.attack(squirtle, charmander)
%Pokemon{name: "Charmander", type: :fire, health: 0, speed: nil, attack: 5}
Use the following type advantages to determine half or double damage.
-
:fire
beats:grass
-
:grass
beats:water
-
:water
beats:fire
battle/2
Create a battle/2
function which:
- accepts two pokemon structs as parameters.
-
attack/2
with the pokemon that has the higher speed. If their speed is the same attack the second pokemon first. - if the attacked pokemon is still above 0 health, attack with the second pokemon.
- returns two updated pokemon structs in a tuple.
For example,
charmander = %Pokemon{name: "Charmander", type: :fire, speed: 20}
squirtle = %Pokemon{name: "Squirtle", type: :water, speed: 10}
PokemonBattle.battle(charmander, squirtle)
{
%Pokemon{name: "Charmander", type: :fire, health: 10, speed: 20, attack: 5},
%Pokemon{name: "Squirtle", type: :water, health: 17.5, speed: 10, attack: 5}
}
charizard = %Pokemon{name: "Charizard", type: :fire, speed: 20, attack: 20}
blastoise = %Pokemon{name: "Blastoise", type: :water, speed: 10, health: 10}
# the faster pokemon will not receive damage if the slower pokemon's health is 0.
PokemonBattle.battle(charizard, blastoise)
{
%Pokemon{name: "Charizard", type: :fire, health: 20, speed: 20, attack: 20},
%Pokemon{name: "Blastoise", type: :water, health: 0, speed: 10, attack: 5}
}
ExUnit.start(auto_run: false)
defmodule Assertion do
use ExUnit.Case
test "" do
defmodule PokemonBattle do
end
assert Keyword.get(Pokemon.__info__(:functions), :__struct__),
"Ensure you complete the `Pokemon` module above first."
assert match?(
%{name: nil, type: nil, speed: nil, health: 20, attack: 5},
struct(Pokemon)
),
"Ensure you complete the `Pokemon` module above first."
pokemon_types =
for speed <- 10..30//5,
type <- [:water, :fire, :grass],
attack <- 5..40//5,
health <- 5..20//5 do
struct(Pokemon, %{
name: "#{Atom.to_string(type)} pokemon",
speed: speed,
attack: attack,
health: health,
type: type
})
end
pokemon_types
|> Enum.shuffle()
|> Enum.take(2)
|> Enum.chunk_every(2)
|> Enum.each(fn [pokemon1, pokemon2] ->
attacked_pokemon = PokemonBattle.attack(pokemon1, pokemon2)
multiplier = Utils.Solutions.PokemonBattle.multiplier(pokemon1, pokemon2)
assert attacked_pokemon == %Pokemon{
pokemon2
| health: pokemon2.health - pokemon1.attack * multiplier
}
PokemonBattle.battle(pokemon1, pokemon2)
assert {battled_pokemon1, battled_pokemon2} = PokemonBattle.battle(pokemon1, pokemon2)
{expected_battled_pokemon1, expected_battled_pokemon2} =
Utils.Solutions.PokemonBattle.battle(pokemon1, pokemon2)
assert battled_pokemon1 == expected_battled_pokemon1
assert battled_pokemon2 == expected_battled_pokemon2
end)
end
end
ExUnit.run()
# Make variables and modules defined in the test available.
# Also allows for exploration using the output of the cell.
defmodule PokemonBattle do
end
Commit Your Progress
Run the following in your command line from the project folder to track and save your progress in a Git commit.
$ git add .
$ git commit -m "finish pokemon battle exercise"