Finished step four: Experience and Levels

This commit is contained in:
Liru 2018-04-20 23:45:23 -04:00
parent 38e8087b1c
commit c069557f17
5 changed files with 102 additions and 2 deletions

View File

@ -2,4 +2,16 @@ defmodule ZombieSurvivor do
@moduledoc """
Documentation for ZombieSurvivor.
"""
@type level :: :blue | :yellow | :orange | :red
@spec level(non_neg_integer) :: level
def level(experience) do
case experience do
x when x > 42 -> :red
x when x > 18 -> :orange
x when x > 6 -> :yellow
_ -> :blue
end
end
end

View File

@ -27,4 +27,11 @@ defmodule ZombieSurvivor.Game do
Survivor.dead?(survivor)
end)
end
@spec level(Game.t()) :: ZombieSurvivor.level()
def level(game) do
game.survivors
|> Enum.reduce(0, fn {_, s}, acc -> max(s.experience, acc) end)
|> ZombieSurvivor.level()
end
end

View File

@ -4,10 +4,11 @@ defmodule ZombieSurvivor.Survivor do
@type t :: %__MODULE__{
name: String.t(),
wounds: non_neg_integer,
equipment: [String.t()]
equipment: [String.t()],
experience: non_neg_integer
}
defstruct name: "", wounds: 0, equipment: []
defstruct name: "", wounds: 0, equipment: [], experience: 0
@spec new([{atom, any}]) :: Survivor.t()
def new(opts \\ []), do: struct(__MODULE__, opts)
@ -15,6 +16,9 @@ defmodule ZombieSurvivor.Survivor do
@spec dead?(Survivor.t()) :: boolean
def dead?(survivor), do: survivor.wounds >= 2
@spec level(Survivor.t()) :: ZombieSurvivor.level()
def level(survivor), do: ZombieSurvivor.level(survivor.experience)
@spec max_actions(Survivor.t()) :: non_neg_integer
def max_actions(_survivor) do
3
@ -26,6 +30,11 @@ defmodule ZombieSurvivor.Survivor do
|> discard_equipment()
end
@spec kill_zombies(Survivor.t(), non_neg_integer) :: Survivor.t()
def kill_zombies(survivor, count \\ 1) do
%{survivor | experience: survivor.experience + count}
end
@spec max_equipment(Survivor.t()) :: non_neg_integer
def max_equipment(%Survivor{} = survivor) do
5 - survivor.wounds

View File

@ -11,6 +11,10 @@ defmodule GameTest do
test "that has 0 survivors" do
assert Map.size(Game.new().survivors) == 0
end
test "that's at level blue" do
assert Game.level(Game.new()) == :blue
end
end
describe "add_survivor/1" do
@ -69,4 +73,32 @@ defmodule GameTest do
refute Game.ended?(g)
end
end
describe "level/1" do
test "returns the level of the highest levelled survivor" do
g =
Game.new()
|> Game.add_survivor(@new_survivor)
assert Game.level(g) == :blue
g =
g
|> Game.add_survivor(Survivor.new(name: "Eric", experience: 10))
assert Game.level(g) == :yellow
g =
g
|> Game.add_survivor(Survivor.new(name: "Jack", experience: 20))
assert Game.level(g) == :orange
g =
g
|> Game.add_survivor(Survivor.new(name: "Liru", experience: 1_000_000))
assert Game.level(g) == :red
end
end
end

View File

@ -14,6 +14,14 @@ defmodule SurvivorTest do
test "gives a survivor with 0 wounds" do
assert %Survivor{wounds: 0} = Survivor.new()
end
test "gives a survivor with 0 experience" do
assert %Survivor{experience: 0} = Survivor.new()
end
test "gives a survivor at level blue" do
assert Survivor.level(Survivor.new()) == :blue
end
end
describe "dead?/1" do
@ -35,6 +43,38 @@ defmodule SurvivorTest do
end
end
describe "kill_zombies/1" do
# TODO: Property testing, always increments
test "increases experience by 1" do
s =
Survivor.new()
|> Survivor.kill_zombies()
assert s.experience == 1
end
end
describe "level/1" do
[
{:blue, :yellow, 6},
{:yellow, :orange, 18},
{:orange, :red, 42}
]
|> Enum.each(fn {old, new, threshold} ->
@old old
@new new
@threshold threshold
test "upgrades from #{@old} to #{@new} when exceeding #{@threshold} experience" do
s = Survivor.new(experience: @threshold)
assert Survivor.level(s) == @old
s = s |> Survivor.kill_zombies()
assert Survivor.level(s) == @new
end
end)
end
describe "max_actions/1" do
test "returns 3 for a new survivor" do
s = Survivor.new()