defmodule Perudex.GameServer do @moduledoc """ This module is a GenServer implementation to control the Perudo game state. """ use GenServer, restart: :transient alias Perudex.{Game, NotifierServer} @type id :: any @type player :: %{id: any, callback_mod: module, callback_arg: any} @type callback_arg :: any @impl true def init({id, players_ids}), do: {:ok, players_ids |> Game.start(5) |> handle_move_result(%{id: id, game: nil})} def start_link({id, players}), do: GenServer.start_link(__MODULE__, {id, Enum.map(players, & &1.id)}, name: service_name(id)) @spec move(id, Game.player_id(), Game.move()) :: any def move(game_id, player_id, move), do: GenServer.call(service_name(game_id), {:move, player_id, move}) @impl true def handle_call({:move, player_id, move}, _from, state), do: {:reply, :ok, state.game |> Game.play_move(player_id, move) |> handle_move_result(state)} defp handle_move_result({instructions, game}, state), do: Enum.reduce(instructions, %{state | game: game}, &handle_instruction(&2, &1)) defp handle_instruction(state, {:notify_player, player_id, instruction_payload}) do NotifierServer.publish(state.id, player_id, instruction_payload) state end defp service_name(game_id), do: Perudex.service_name({__MODULE__, game_id}) end