Packages
islands_engine
0.2.47
0.2.65
0.2.64
0.2.63
0.2.62
0.2.61
0.2.60
0.2.59
0.2.58
0.2.56
0.2.55
0.2.54
0.2.53
0.2.52
0.2.51
0.2.50
0.2.49
0.2.48
0.2.47
0.2.46
0.2.45
0.2.44
0.2.43
0.2.42
0.2.41
0.2.40
0.2.39
0.2.38
0.2.37
0.2.36
0.2.35
0.2.34
0.2.33
0.2.32
0.2.31
0.2.30
0.2.29
0.2.28
0.2.27
0.2.25
0.2.24
0.2.23
0.2.22
0.2.21
0.2.20
0.2.19
0.2.18
0.2.17
0.2.16
0.2.15
0.2.13
0.2.12
0.2.10
0.2.9
0.2.8
0.2.7
0.2.6
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
0.1.81
0.1.80
0.1.79
0.1.78
0.1.77
0.1.76
0.1.75
0.1.73
0.1.72
0.1.71
0.1.70
0.1.69
0.1.68
0.1.67
0.1.66
0.1.65
0.1.64
0.1.63
0.1.62
0.1.61
0.1.60
0.1.59
0.1.58
0.1.57
0.1.56
0.1.55
0.1.54
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.38
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.5
0.1.4
0.1.0
Models the Game of Islands.
Current section
Files
Jump to
Current section
Files
lib/islands/engine.ex
# ┌────────────────────────────────────────────────────────────────────┐
# │ Based on the book "Functional Web Development" by Lance Halvorsen. │
# └────────────────────────────────────────────────────────────────────┘
defmodule Islands.Engine do
@moduledoc """
Models the _Game of Islands_.
##### Based on the book [Functional Web Development](https://pragprog.com/book/lhelph/functional-web-development-with-elixir-otp-and-phoenix) by Lance Halvorsen.
"""
use GenServer.Proxy
import Islands.Engine.Guards
alias Islands.Engine.{DynGameSup, GameServer}
alias Islands.{Coord, Game, Island, Player, PlayerID, Tally}
@doc """
Starts a new game server process and supervises it.
"""
@spec new_game(Game.name(), Player.name(), Player.gender(), pid) ::
Supervisor.on_start_child()
def new_game(game_name, player1_name, gender, pid)
when valid?(game_name, player1_name, gender, pid) do
child_spec = {GameServer, {game_name, player1_name, gender, pid}}
DynamicSupervisor.start_child(DynGameSup, child_spec)
end
@doc """
Stops a game server process normally. It won't be restarted.
"""
@spec end_game(Game.name()) :: :ok | {:error, term}
def end_game(game_name) when is_binary(game_name),
do: stop(:shutdown, game_name)
@doc """
Stops a game at a player's request.
"""
@spec stop_game(Game.name(), PlayerID.t()) :: Tally.t() | {:error, term}
def stop_game(game_name, player_id) when valid?(game_name, player_id),
do: call({:stop, player_id}, game_name)
@doc """
Adds the second player of a game.
"""
@spec add_player(Game.name(), Player.name(), Player.gender(), pid) ::
Tally.t() | {:error, term}
def add_player(game_name, player2_name, gender, pid)
when valid?(game_name, player2_name, gender, pid),
do: call({:add_player, player2_name, gender, pid}, game_name)
@doc """
Positions an island on the specified player's board.
"""
@spec position_island(
Game.name(),
PlayerID.t(),
Island.type(),
Coord.row(),
Coord.col()
) :: Tally.t() | {:error, term}
def position_island(game_name, player_id, island_type, row, col)
when valid?(game_name, player_id, island_type, row, col),
do: call({:position_island, player_id, island_type, row, col}, game_name)
@doc """
Positions all islands on the specified player's board.
"""
@spec position_all_islands(Game.name(), PlayerID.t()) ::
Tally.t() | {:error, term}
def position_all_islands(game_name, player_id)
when valid?(game_name, player_id),
do: call({:position_all_islands, player_id}, game_name)
@doc """
Declares all islands set for the specified player.
"""
@spec set_islands(Game.name(), PlayerID.t()) :: Tally.t() | {:error, term}
def set_islands(game_name, player_id) when valid?(game_name, player_id),
do: call({:set_islands, player_id}, game_name)
@doc """
Lets the specified player guess square (`row`, `col`).
"""
@spec guess_coord(Game.name(), PlayerID.t(), Coord.row(), Coord.col()) ::
Tally.t() | {:error, term}
def guess_coord(game_name, player_id, row, col)
when valid_args?(game_name, player_id, row, col),
do: call({:guess_coord, player_id, row, col}, game_name)
@doc """
Returns the tally of a game for the specified player.
"""
@spec tally(Game.name(), PlayerID.t()) :: Tally.t() | {:error, term}
def tally(game_name, player_id) when valid?(game_name, player_id),
do: call({:tally, player_id}, game_name)
@doc """
Returns an overview of all the games being played.
"""
@spec games_overview :: [Game.overview()]
def games_overview do
GenServer.call(GameRecovery, :games_overview)
end
@doc """
Returns a sorted list of registered game names.
"""
@spec game_names :: [Game.name()]
def game_names do
:global.registered_names()
|> Enum.map(&game_name/1)
|> Enum.reject(&is_nil/1)
|> Enum.sort()
end
@doc """
Returns the `pid` of the game server process registered via the
given `game_name`, or `nil` if no such process is registered.
"""
@spec game_pid(Game.name()) :: pid | nil
def game_pid(game_name),
do: GameServer.via(game_name) |> GenServer.whereis()
## Private functions
@spec game_name(term) :: Game.name() | atom
defp game_name({GameServer, game_name}), do: game_name
defp game_name(_), do: nil
end