Packages
islands_game
0.1.13
0.1.53
0.1.52
0.1.51
0.1.50
0.1.49
0.1.48
0.1.47
0.1.46
0.1.45
0.1.44
0.1.43
0.1.42
0.1.41
0.1.40
0.1.39
0.1.37
0.1.36
0.1.35
0.1.34
0.1.33
0.1.32
0.1.31
0.1.30
0.1.29
0.1.28
0.1.27
0.1.26
0.1.25
0.1.24
0.1.23
0.1.22
0.1.21
0.1.20
0.1.19
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
A game struct and functions for the Game of Islands.
Current section
Files
Jump to
Current section
Files
lib/islands/game.ex
# ┌───────────────────────────────────────────────────────────────────────┐
# │ Inspired by the book "Functional Web Development" by Lance Halvorsen. │
# └───────────────────────────────────────────────────────────────────────┘
defmodule Islands.Game do
@behaviour Access
use PersistConfig
@book_ref Application.get_env(@app, :book_ref)
@moduledoc """
Models a `game` in the _Game of Islands_.
\n##### #{@book_ref}
"""
alias __MODULE__
alias Islands.{
Board,
Coord,
Guesses,
Player,
PlayerID,
Request,
Response,
State
}
@genders [:f, :m]
@hit_or_miss [:hit, :miss]
@player_ids [:player1, :player2]
@derive [Poison.Encoder]
@derive Jason.Encoder
@enforce_keys [:name, :player1, :player2]
defstruct name: nil,
player1: nil,
player2: nil,
request: {},
response: {},
state: State.new()
@type t :: %Game{
name: String.t(),
player1: Player.t(),
player2: Player.t(),
request: Request.t(),
response: Response.t(),
state: State.t()
}
# Access behaviour
defdelegate fetch(game, key), to: Map
defdelegate get(game, key, default), to: Map
defdelegate get_and_update(game, key, fun), to: Map
defdelegate pop(game, key), to: Map
@spec new(String.t(), String.t(), Player.gender(), pid) :: t | {:error, atom}
def new(name, player1_name, gender, pid)
when is_binary(name) and is_binary(player1_name) and is_pid(pid) and
gender in @genders do
%Game{
name: name,
player1: Player.new(player1_name, gender, pid),
player2: Player.new("?", :f, nil)
}
end
def new(_name, _player1_name, _gender, _pid), do: {:error, :invalid_game_args}
@spec update_board(t, PlayerID.t(), Board.t()) :: t
def update_board(%Game{} = game, player_id, %Board{} = board)
when player_id in @player_ids,
do: put_in(game[player_id].board, board)
@spec update_guesses(t, PlayerID.t(), Guesses.type(), Coord.t()) :: t
def update_guesses(%Game{} = game, player_id, hit_or_miss, %Coord{} = guess)
when player_id in @player_ids and hit_or_miss in @hit_or_miss do
update_in(game[player_id].guesses, &Guesses.add(&1, hit_or_miss, guess))
end
@spec update_player(t, PlayerID.t(), String.t(), Player.gender(), pid) :: t
def update_player(%Game{} = game, player_id, name, gender, pid)
when player_id in @player_ids and is_binary(name) and is_pid(pid) and
gender in @genders do
player = %Player{game[player_id] | name: name, gender: gender, pid: pid}
put_in(game[player_id], player)
end
@spec notify_player(t, PlayerID.t()) :: t
def notify_player(%Game{} = game, player_id) when player_id in @player_ids do
send(game[player_id].pid, game.state.game_state)
game
end
@spec player_board(t, PlayerID.t()) :: Board.t()
def player_board(%Game{} = game, player_id) when player_id in @player_ids,
do: game[player_id].board
@spec opponent_id(PlayerID.t()) :: PlayerID.t()
def opponent_id(:player1), do: :player2
def opponent_id(:player2), do: :player1
@spec update_state(t, State.t()) :: t
def update_state(%Game{} = game, %State{} = state),
do: put_in(game.state, state)
@spec update_request(t, Request.t()) :: t
def update_request(%Game{} = game, request) when is_tuple(request),
do: put_in(game.request, request)
@spec update_response(t, Response.t()) :: t
def update_response(%Game{} = game, response) when is_tuple(response),
do: put_in(game.response, response)
defimpl Poison.Encoder, for: Tuple do
def encode(data, options) when is_tuple(data) do
data |> Tuple.to_list() |> Poison.Encoder.List.encode(options)
end
end
defimpl Jason.Encoder, for: Tuple do
def encode(data, opts) when is_tuple(data) do
data |> Tuple.to_list() |> Jason.Encode.list(opts)
end
end
end