Improved infrastructure for step five

This commit is contained in:
Liru 2018-04-21 00:48:17 -04:00
parent 542ffbc826
commit 7e20cac9c1
2 changed files with 134 additions and 96 deletions

View File

@ -1,9 +1,25 @@
defmodule ZombieSurvivor.Game do defmodule ZombieSurvivor.Game do
alias ZombieSurvivor.{Game, Survivor} alias ZombieSurvivor.{Game, Survivor}
@type t :: %__MODULE__{survivors: %{String.t() => Survivor.t()}} defmodule State do
alias __MODULE__, as: Game
defstruct survivors: %{} @type t :: %__MODULE__{
survivors: %{String.t() => Survivor.t()},
history: [String.t()]
}
@type history_type ::
:start
| :new_survivor
| :new_equipment
| :wounded
| :death
| :levelup
| :game_levelup
| :end
@type history :: {history_type, any}
defstruct survivors: %{}, history: []
@spec new() :: Game.t() @spec new() :: Game.t()
def new(), do: %Game{} def new(), do: %Game{}
@ -35,4 +51,48 @@ defmodule ZombieSurvivor.Game do
|> Enum.reduce(0, fn {_, s}, acc -> max(s.experience, acc) end) |> Enum.reduce(0, fn {_, s}, acc -> max(s.experience, acc) end)
|> ZombieSurvivor.level() |> ZombieSurvivor.level()
end end
end
use GenServer
def new, do: start_link()
def add_survivor(pid, survivor), do: GenServer.cast(pid, {:add_survivor, survivor})
def ended?(pid), do: GenServer.call(pid, :ended?)
def history(pid), do: GenServer.call(pid, :history)
def level(pid), do: GenServer.call(pid, :level)
def survivors(pid), do: GenServer.call(pid, :survivors)
## Server callbacks
def start_link(opts \\ []) do
GenServer.start_link(__MODULE__, :ok, opts)
end
@impl GenServer
def init(:ok) do
{:ok, State.new()}
end
@impl GenServer
def handle_call(:ended?, _from, state) do
{:reply, State.ended?(state), state}
end
def handle_call(:history, _from, state) do
{:reply, state.history, state}
end
def handle_call(:level, _from, state) do
{:reply, State.level(state), state}
end
def handle_call(:survivors, _from, state) do
{:reply, state.survivors, state}
end
@impl GenServer
def handle_cast({:add_survivor, survivor}, state) do
{:noreply, State.add_survivor(state, survivor)}
end
end end

View File

@ -7,124 +7,102 @@ defmodule GameTest do
@new_survivor Survivor.new(name: "Zombait") @new_survivor Survivor.new(name: "Zombait")
@dead_survivor Survivor.new(name: "Deadman", wounds: 2) @dead_survivor Survivor.new(name: "Deadman", wounds: 2)
describe "new/0 starts a game" do setup do
test "that has 0 survivors" do game = start_supervised!(Game)
assert Map.size(Game.new().survivors) == 0 %{game: game}
end end
test "that's at level blue" do describe "new/0 starts a game" do
assert Game.level(Game.new()) == :blue test "that has 0 survivors", %{game: game} do
assert Map.size(Game.survivors(game)) == 0
end
test "that's at level blue", %{game: game} do
assert Game.level(game) == :blue
end end
end end
describe "add_survivor/1" do describe "add_survivor/1" do
test "adds a survivor to a game" do test "adds a survivor to a game", %{game: game} do
g = Game.add_survivor(game, @new_survivor)
Game.new()
|> Game.add_survivor(@new_survivor)
assert Map.size(g.survivors) == 1 assert Map.size(Game.survivors(game)) == 1
g = Game.add_survivor(game, %{@new_survivor | name: "Larry"})
g
|> Game.add_survivor(%{@new_survivor | name: "Larry"})
assert Map.size(g.survivors) == 2 assert Map.size(Game.survivors(game)) == 2
end end
test "ensures that two survivors with the same name can't exist" do test "ensures that two survivors with the same name can't exist", %{game: game} do
g = game
Game.new()
|> Game.add_survivor(@new_survivor) |> Game.add_survivor(@new_survivor)
|> Game.add_survivor(@new_survivor) |> Game.add_survivor(@new_survivor)
assert Map.size(g.survivors) == 1 assert Map.size(Game.survivors(game)) == 1
end end
end end
describe "ended?/1" do describe "ended?/1" do
test "returns true if all its survivors are dead" do test "returns true if all its survivors are dead", %{game: game} do
# TODO: Property test, add many dead survivors # TODO: Property test, add many dead survivors
g = game
Game.new()
|> Game.add_survivor(@dead_survivor) |> Game.add_survivor(@dead_survivor)
assert Game.ended?(g) assert Game.ended?(game)
g = game
g
|> Game.add_survivor(%{@dead_survivor | name: "Zambee"}) |> Game.add_survivor(%{@dead_survivor | name: "Zambee"})
assert Game.ended?(g) assert Game.ended?(game)
end end
test "returns false if at least one survivor is alive" do test "returns false if at least one survivor is alive", %{game: game} do
g = game
Game.new()
|> Game.add_survivor(@new_survivor) |> Game.add_survivor(@new_survivor)
|> Game.add_survivor(@dead_survivor) |> Game.add_survivor(@dead_survivor)
refute Game.ended?(g) refute Game.ended?(game)
end end
test "returns false if no survivors joined" do test "returns false if no survivors joined", %{game: game} do
g = Game.new() refute Game.ended?(game)
refute Game.ended?(g)
end end
end end
describe "level/1" do describe "level/1" do
test "returns the level of the highest levelled survivor" do test "returns the level of the highest levelled survivor", %{game: game} do
g = Game.add_survivor(game, @new_survivor)
Game.new()
|> Game.add_survivor(@new_survivor)
assert Game.level(g) == :blue assert Game.level(game) == :blue
g = Game.add_survivor(game, Survivor.new(name: "Eric", experience: 10))
g
|> Game.add_survivor(Survivor.new(name: "Eric", experience: 10))
assert Game.level(g) == :yellow assert Game.level(game) == :yellow
g = Game.add_survivor(game, Survivor.new(name: "Jack", experience: 20))
g
|> Game.add_survivor(Survivor.new(name: "Jack", experience: 20))
assert Game.level(g) == :orange assert Game.level(game) == :orange
Game.add_survivor(game, Survivor.new(name: "Liru", experience: 1_000_000))
g = assert Game.level(game) == :red
g
|> Game.add_survivor(Survivor.new(name: "Liru", experience: 1_000_000))
assert Game.level(g) == :red
end end
test "returns the level of the highest levelled living survivor" do test "returns the level of the highest levelled living survivor", %{game: game} do
g = Game.add_survivor(game, @new_survivor)
Game.new()
|> Game.add_survivor(@new_survivor)
assert Game.level(g) == :blue assert Game.level(game) == :blue
g = Game.add_survivor(game, Survivor.new(name: "Eric", experience: 10))
g
|> Game.add_survivor(Survivor.new(name: "Eric", experience: 10))
assert Game.level(g) == :yellow assert Game.level(game) == :yellow
g = Game.add_survivor(game, %{@dead_survivor | name: "Jack", experience: 20})
g
|> Game.add_survivor(Survivor.new(name: "Jack", experience: 20, wounds: 2))
assert Game.level(g) == :yellow assert Game.level(game) == :yellow
g = Game.add_survivor(game, %{@dead_survivor | name: "Fake Liru", experience: 1_000_000})
g
|> Game.add_survivor(Survivor.new(name: "Liru", experience: 1_000_000, wounds: 2))
assert Game.level(g) == :yellow assert Game.level(game) == :yellow
end end
end end
end end