Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Elixir - Tic Tac Toe

Avatar for Felipe Renan Felipe Renan
January 01, 2019
44

Elixir - Tic Tac Toe

Avatar for Felipe Renan

Felipe Renan

January 01, 2019
Tweet

Transcript

  1. A idéia de fazer esse jogo foi para aprender mais

    sobre a linguagem fazendo algo prático.
  2. 4 É um processo da VM do Erlang e não

    do SO. 4 São extremamente leves. 4 Podemos criar milhares deles. 4 Não compartilham mémoria entre si.
  3. Exemplo sem utilizar um processo sum = fn(x, y) ->

    # Simulando um processamento longo. Essa operação irá demorar 2s. :timer.sleep(2000) x + y end
  4. Exemplo sem utilizar um processo sum = fn(x, y) ->

    # Simulando um processamento longo. Essa operação irá demorar 2s. :timer.sleep(2000) x + y end sum.(2, 2) 4 # depois de 2 segundos.
  5. Exemplo sem utilizar um processo sum = fn(x, y) ->

    # Simulando um processamento longo. Essa operação irá demorar 2s. :timer.sleep(2000) x + y end Enum.map(1..3, &sum.(&1, 2)) [3, 4, 5] # depois de 6 segundos.
  6. Exemplo sem utilizar um processo Enum.map(1..3, &sum.(&1, 2)) # 6s

    até retornar todos os resultados. Enum.map(1..5, &sum.(&1, 2)) # 10s até retornar todos os resultados. Enum.map(1..10, &sum.(&1, 2)) # 20s até retornar todos os resultados.
  7. Exemplo utilizando um processo sum = fn(x, y) -> #

    Simulando um processamento longo. Essa operação irá demorar 2s. :timer.sleep(2000) x + y end # Função que irá executar a `sum/2` em um processo. sum_async = fn (x, y) -> spawn(fn -> IO.inspect sum.(x, y) end) end
  8. Exemplo utilizando um processo Enum.each(1..3, &sum_async.(&1, 2)) # 2s até

    retornar todos os resultados. Enum.each(1..5, &sum_async.(&1, 2)) # 2s até retornar todos os resultados. Enum.each(1..10, &sum_async.(&1, 2)) # 2s até retornar todos os resultados.
  9. GenServer 4 Um behaviour. 4 É um processo como qualquer

    outro em Elixir. 4 Pode ser usado para manter estado. https://hexdocs.pm/elixir/GenServer.html
  10. defmodule ListCache do use GenServer @impl true def init(list \\

    []) do {:ok, list} end @impl true def handle_call(:show_items, _from, state) do {:reply, state, state} end @impl true def handle_call({:add, item}, _from, state) do new_state = [item | state] {:reply, new_state, new_state} end @impl true def handle_call({:remove, item}, _from, state) do new_state = List.delete(state, item) {:reply, new_state, new_state} end end
  11. defmodule ListCache do use GenServer @impl true def init(list \\

    []) do {:ok, list} end @impl true def handle_call(:show_items, _from, state) do {:reply, state, state} end @impl true def handle_call({:add, item}, _from, state) do new_state = [item | state] {:reply, new_state, new_state} end @impl true def handle_call({:remove, item}, _from, state) do new_state = List.delete(state, item) {:reply, new_state, new_state} end end
  12. defmodule ListCache do use GenServer @impl true def init(list \\

    []) do {:ok, list} end @impl true def handle_call(:show_items, _from, state) do {:reply, state, state} end @impl true def handle_call({:add, item}, _from, state) do new_state = [item | state] {:reply, new_state, new_state} end @impl true def handle_call({:remove, item}, _from, state) do new_state = List.delete(state, item) {:reply, new_state, new_state} end end
  13. defmodule ListCache do use GenServer @impl true def init(list \\

    []) do {:ok, list} end @impl true def handle_call(:show_items, _from, state) do {:reply, state, state} end @impl true def handle_call({:add, item}, _from, state) do new_state = [item | state] {:reply, new_state, new_state} end @impl true def handle_call({:remove, item}, _from, state) do new_state = List.delete(state, item) {:reply, new_state, new_state} end end
  14. {:ok, pid} = GenServer.start_link(ListCache, [:hello, :world]) GenServer.call(pid, :show) [:hello, :world]

    GenServer.call(pid, {:add, :felipe}) [:hello, :world, :felipe] GenServer.call(pid, {:remove, :felipe})
  15. defmodule ListCache do use GenServer @impl true def init(list \\

    []) do {:ok, list} end @impl true def handle_call(:show_items, _from, state) do {:reply, state, state} end @impl true def handle_call({:add, item}, _from, state) do new_state = [item | state] {:reply, new_state, new_state} end @impl true def handle_call({:remove, item}, _from, state) do new_state = List.delete(state, item) {:reply, new_state, new_state} end end
  16. {:ok, pid} = GenServer.start_link(ListCache, [:hello, :world]) GenServer.call(pid, :show) [:hello, :world]

    GenServer.call(pid, {:add, :felipe}) [:hello, :world, :felipe] GenServer.call(pid, {:remove, :felipe}) [:hello, :world]
  17. defmodule ListCache do use GenServer def start_link(default) do GenServer.start_link(__MODULE__, default)

    end def add(pid, item) do GenServer.call(pid, {:add, item}) end def remove(pid, position) do GenServer.call(pid, {:remove, position}) end def show_items(pid) do GenServer.call(pid, :show_items) end ... end
  18. GenServer summary 4 É um processo como qualquer outro em

    Elixir. 4 Usado para manter estados e processar mensagens.
  19. defmodule GameEngine.Board do @moduledoc """ Struct and functions to control

    a game board. """ defstruct positions: [ nil, nil, nil, nil, nil, nil, nil, nil, nil ] ... end
  20. defmodule GameEngine.Game do @moduledoc """ Struct and functions to control

    a game state. """ alias GameEngine.Board defstruct board: %Board{}, x: nil, o: nil, next: :x, first: :x, finished: false, winner: nil ... end
  21. %GameEngine.Game{ board: %GameEngine.Board{ positions: [ nil, nil, nil, nil, nil,

    nil, nil, nil, nil ] }, finished: false, first: :x, next: :x, o: nil, x: nil, winner: nil }
  22. defmodule GameEngine.GameServer do @moduledoc """ Create a process for a

    game with two players. """ use GenServer def start_link(name) do GenServer.start_link(__MODULE__, nil, name: via_tuple(name)) end def join_player(game, player) do GenServer.call(via_tuple(game), {:join_player, player}) end def put_player_symbol(game, symbol, pos) do GenServer.call(via_tuple(game), {:put_player_symbol, symbol, pos}) end def new_round(game) do GenServer.call(via_tuple(game), :new_round) end def leave(game, symbol) do GenServer.cast(via_tuple(game), {:leave, symbol}) end defp via_tuple(name) do {:via, GameRegistry, name} end ... end
  23. defmodule GameEngine.GameServer do ... def start_link(name) do GenServer.start_link(__MODULE__, nil, name:

    via_tuple(name)) end ... @impl true def init(_) do {:ok, %Game{}} end ... end
  24. defmodule GameEngine.GameServer do ... def start_link(name) do GenServer.start_link(__MODULE__, nil, name:

    via_tuple(name)) end ... @impl true def init(_) do {:ok, %Game{}} end ... end
  25. alias GameEngine.{Game, GameServer, Board} GameServer.start_link("my-game") %GameEngine.Game{ board: %GameEngine.Board{ positions: [nil,

    nil, nil, nil, nil, nil, nil, nil, nil] }, finished: false, first: :x, next: :x, o: nil, x: nil, winner: nil }
  26. defmodule GameEngine.GameServer do ... def join_player(game, player) do GenServer.call(via_tuple(game), {:join_player,

    player}) end ... @impl true def handle_call({:join_player, player}, _from, %{x: nil} = state) do new_state = %{state | x: player} {:reply, {:ok, :x, new_state}, new_state} end ... end
  27. defmodule GameEngine.GameServer do ... def join_player(game, player) do GenServer.call(via_tuple(game), {:join_player,

    player}) end ... @impl true def handle_call({:join_player, player}, _from, %{x: nil} = state) do new_state = %{state | x: player} {:reply, {:ok, :x, new_state}, new_state} end ... end
  28. {:ok, player_x, game} = GameServer.join_player("my-game", "Felipe") %GameEngine.Game{ board: %GameEngine.Board{ positions:

    [nil, nil, nil, nil, nil, nil, nil, nil, nil] }, finished: false, first: :x, next: :x, o: nil, x: "Felipe", winner: nil }
  29. defmodule GameEngine.GameServer do ... def join_player(game, player) do GenServer.call(via_tuple(game), {:join_player,

    player}) end ... @impl true def handle_call({:join_player, player}, _from, %{o: nil} = state) do new_state = %{state | o: player} {:reply, {:ok, :o, new_state}, new_state} end ... end
  30. {:ok, player_o, game} = GameServer.join_player("my-game", "Renan") %GameEngine.Game{ board: %GameEngine.Board{ positions:

    [nil, nil, nil, nil, nil, nil, nil, nil, nil] }, finished: false, first: :x, next: :x, o: "Renan", x: "Felipe", winner: nil }
  31. defmodule GameEngine.GameServer do ... def put_player_symbol(game, symbol, pos) do GenServer.call(via_tuple(game),

    {:put_player_symbol, symbol, pos}) end ... @impl true def handle_call({:put_player_symbol, _symbol, _pos}, _from, %Game{finished: true} = state) do {:reply, :finished, state} end @impl true def handle_call({:put_player_symbol, symbol, position}, _from, %Game{next: symbol} = state) do ... end ... end
  32. defmodule GameEngine.GameServer do ... def put_player_symbol(game, symbol, pos) do GenServer.call(via_tuple(game),

    {:put_player_symbol, symbol, pos}) end ... @impl true def handle_call({:put_player_symbol, _symbol, _pos}, _from, %Game{finished: true} = state) do {:reply, :finished, state} end @impl true def handle_call({:put_player_symbol, symbol, position}, _from, %Game{next: symbol} = state) do ... end ... end
  33. defmodule GameEngine.GameServer do ... def put_player_symbol(game, symbol, pos) do GenServer.call(via_tuple(game),

    {:put_player_symbol, symbol, pos}) end ... @impl true def handle_call({:put_player_symbol, _symbol, _pos}, _from, %Game{finished: true} = state) do {:reply, :finished, state} end @impl true def handle_call({:put_player_symbol, symbol, position}, _from, %Game{next: symbol} = state) do ... end ... end
  34. defmodule GameEngine.GameServer do ... def handle_call({:put_player_symbol, symbol, position}, _from, %Game{next:

    symbol} = state) do case Board.put(state.board, position, symbol) do {:error, error_message} -> {:reply, {:retry, error_message}, state} board -> state = %{state | board: board} cond do winner = Board.winner(board) -> new_state = Game.finish(state, winner) {:reply, {:winner, new_state}, new_state} Board.full?(board) -> new_state = Game.finish(state, :draw) {:reply, {:draw, new_state}, new_state} true -> new_state = Game.next_turn(state) {:reply, {:ok, new_state}, new_state} end end end ... end
  35. defmodule GameEngine.Board do @symbols [:x, :o] ... def put(board, pos,

    symbol) when symbol in @symbols and pos >= 0 and pos <= 8 do case Enum.at(board.positions, pos) do nil -> new_positions = List.replace_at(board.positions, pos, symbol) %__MODULE__{board | positions: new_positions} existent_symbol -> {:error, "The position: #{pos} already has the symbol: #{existent_symbol}"} end end ... end
  36. defmodule GameEngine.Board do @symbols [:x, :o] ... def put(board, pos,

    symbol) when symbol in @symbols and pos >= 0 and pos <= 8 do case Enum.at(board.positions, pos) do nil -> new_positions = List.replace_at(board.positions, pos, symbol) %__MODULE__{board | positions: new_positions} existent_symbol -> {:error, "The position: #{pos} already has the symbol: #{existent_symbol}"} end end ... end
  37. defmodule GameEngine.Board do @symbols [:x, :o] ... def put(board, pos,

    symbol) when symbol in @symbols and pos >= 0 and pos <= 8 do case Enum.at(board.positions, pos) do nil -> new_positions = List.replace_at(board.positions, pos, symbol) %__MODULE__{board | positions: new_positions} existent_symbol -> {:error, "The position: #{pos} already has the symbol: #{existent_symbol}"} end end ... end
  38. defmodule GameEngine.GameServer do ... def handle_call({:put_player_symbol, symbol, position}, _from, %Game{next:

    symbol} = state) do case Board.put(state.board, position, symbol) do {:error, error_message} -> {:reply, {:retry, error_message}, state} board -> state = %{state | board: board} cond do winner = Board.winner(board) -> new_state = Game.finish(state, winner) {:reply, {:winner, new_state}, new_state} Board.full?(board) -> new_state = Game.finish(state, :draw) {:reply, {:draw, new_state}, new_state} true -> new_state = Game.next_turn(state) {:reply, {:ok, new_state}, new_state} end end end ... end
  39. defmodule GameEngine.GameServer do ... def handle_call({:put_player_symbol, symbol, position}, _from, %Game{next:

    symbol} = state) do case Board.put(state.board, position, symbol) do {:error, error_message} -> {:reply, {:retry, error_message}, state} board -> state = %{state | board: board} cond do winner = Board.winner(board) -> new_state = Game.finish(state, winner) {:reply, {:winner, new_state}, new_state} Board.full?(board) -> new_state = Game.finish(state, :draw) {:reply, {:draw, new_state}, new_state} true -> new_state = Game.next_turn(state) {:reply, {:ok, new_state}, new_state} end end end ... end
  40. defmodule GameEngine.Board do ... defp do_winner([ s, s, s, _,

    _, _, _, _, _ ]) when s in @symbols, do: s ... defp do_winner([ s, _, _, s, _, _, s, _, _ ]) when s in @symbols, do: s ... defp do_winner([ _, _, s, _, _, s, _, _, s ]) when s in @symbols, do: s defp do_winner([ s, _, _, _, s, _, _, _, s ]) when s in @symbols, do: s ... defp do_winner(_), do: nil end
  41. defmodule GameEngine.Board do ... defp do_winner([ s, s, s, _,

    _, _, _, _, _ ]) when s in @symbols, do: s ... defp do_winner([ s, _, _, s, _, _, s, _, _ ]) when s in @symbols, do: s ... defp do_winner([ _, _, s, _, _, s, _, _, s ]) when s in @symbols, do: s defp do_winner([ s, _, _, _, s, _, _, _, s ]) when s in @symbols, do: s ... defp do_winner(_), do: nil end
  42. defmodule GameEngine.GameServer do ... def handle_call({:put_player_symbol, symbol, position}, _from, %Game{next:

    symbol} = state) do case Board.put(state.board, position, symbol) do {:error, error_message} -> {:reply, {:retry, error_message}, state} board -> state = %{state | board: board} cond do winner = Board.winner(board) -> new_state = Game.finish(state, winner) {:reply, {:winner, new_state}, new_state} Board.full?(board) -> new_state = Game.finish(state, :draw) {:reply, {:draw, new_state}, new_state} true -> new_state = Game.next_turn(state) {:reply, {:ok, new_state}, new_state} end end end ... end
  43. defmodule GameEngine.GameServer do ... def handle_call({:put_player_symbol, symbol, position}, _from, %Game{next:

    symbol} = state) do case Board.put(state.board, position, symbol) do {:error, error_message} -> {:reply, {:retry, error_message}, state} board -> state = %{state | board: board} cond do winner = Board.winner(board) -> new_state = Game.finish(state, winner) {:reply, {:winner, new_state}, new_state} Board.full?(board) -> new_state = Game.finish(state, :draw) {:reply, {:draw, new_state}, new_state} true -> new_state = Game.next_turn(state) {:reply, {:ok, new_state}, new_state} end end end ... end
  44. defmodule GameEngine.GameServer do ... def handle_call({:put_player_symbol, symbol, position}, _from, %Game{next:

    symbol} = state) do case Board.put(state.board, position, symbol) do {:error, error_message} -> {:reply, {:retry, error_message}, state} board -> state = %{state | board: board} cond do winner = Board.winner(board) -> new_state = Game.finish(state, winner) {:reply, {:winner, new_state}, new_state} Board.full?(board) -> new_state = Game.finish(state, :draw) {:reply, {:draw, new_state}, new_state} true -> new_state = Game.next_turn(state) {:reply, {:ok, new_state}, new_state} end end end ... end
  45. defmodule GameEngine.Game do ... def next_turn(%__MODULE__{next: :x} = game), do:

    %__MODULE__{game | next: :o} def next_turn(%__MODULE__{next: :o} = game), do: %__MODULE__{game | next: :x} ... end
  46. defmodule GameEngine.Game do ... def next_turn(%__MODULE__{next: :x} = game), do:

    %__MODULE__{game | next: :o} def next_turn(%__MODULE__{next: :o} = game), do: %__MODULE__{game | next: :x} ... end
  47. GameServer.put_player_symbol("my-game", player_x, 1) %GameEngine.Game{ board: %GameEngine.Board{ positions: [nil, :x, nil,

    nil, nil, nil, nil, nil, nil] }, finished: false, first: :x, next: :o, o: "Renan", x: "Felipe", winner: nil }
  48. GameServer.put_player_symbol("my-game", player_o, 8) %GameEngine.Game{ board: %GameEngine.Board{ positions: [nil, :x, nil,

    nil, nil, nil, nil, nil, :o] }, finished: false, first: :x, next: :x, o: "Renan", x: "Felipe", winner: nil }
  49. GameServer.put_player_symbol("my-game", player_x, 0) %GameEngine.Game{ board: %GameEngine.Board{ positions: [:x, :x, nil,

    nil, nil, nil, nil, nil, :o] }, finished: false, first: :x, next: :o, o: "Renan", x: "Felipe", winner: nil }
  50. GameServer.put_player_symbol("my-game", player_o, 7) %GameEngine.Game{ board: %GameEngine.Board{ positions: [:x, :x, nil,

    nil, nil, nil, nil, :o, :o] }, finished: false, first: :x, next: :x, o: "Renan", x: "Felipe", winner: nil }
  51. defmodule GameEngine.GameServer do ... def handle_call({:put_player_symbol, symbol, position}, _from, %Game{next:

    symbol} = state) do case Board.put(state.board, position, symbol) do {:error, error_message} -> {:reply, {:retry, error_message}, state} board -> state = %{state | board: board} cond do winner = Board.winner(board) -> new_state = Game.finish(state, winner) {:reply, {:winner, new_state}, new_state} Board.full?(board) -> new_state = Game.finish(state, :draw) {:reply, {:draw, new_state}, new_state} true -> new_state = Game.next_turn(state) {:reply, {:ok, new_state}, new_state} end end end ... end
  52. defmodule GameEngine.Board do ... defp do_winner([ s, s, s, _,

    _, _, _, _, _ ]) when s in @symbols, do: s ... end
  53. defmodule GameEngine.GameServer do ... def handle_call({:put_player_symbol, symbol, position}, _from, %Game{next:

    symbol} = state) do case Board.put(state.board, position, symbol) do {:error, error_message} -> {:reply, {:retry, error_message}, state} board -> state = %{state | board: board} cond do winner = Board.winner(board) -> new_state = Game.finish(state, winner) {:reply, {:winner, new_state}, new_state} Board.full?(board) -> new_state = Game.finish(state, :draw) {:reply, {:draw, new_state}, new_state} true -> new_state = Game.next_turn(state) {:reply, {:ok, new_state}, new_state} end end end ... end
  54. GameServer.put_player_symbol("my-game", player_x, 2) %GameEngine.Game{ board: %GameEngine.Board{ positions: [:x, :x, :x,

    nil, nil, nil, nil, :o, :o] }, finished: true, first: :x, next: :o, o: "Renan", x: "Felipe", winner: :x }
  55. defmodule GameEngine.GameSupervisor do alias GameEngine.GameServer use DynamicSupervisor def start_link(_) do

    DynamicSupervisor.start_link(__MODULE__, nil, name: __MODULE__) end def init(_) do DynamicSupervisor.init(strategy: :one_for_one) end def create_game(name) do child_spec = %{ id: GameServer, start: {GameServer, :start_link, [name]}, restart: :temporary } DynamicSupervisor.start_child(__MODULE__, child_spec) end def game_exists?(game_name) do case Registry.lookup(:game_server_registry, game_name) do [] -> false _ -> true end end end
  56. defmodule GameEngine.GameSupervisor do alias GameEngine.GameServer use DynamicSupervisor def start_link(_) do

    DynamicSupervisor.start_link(__MODULE__, nil, name: __MODULE__) end def init(_) do DynamicSupervisor.init(strategy: :one_for_one) end def create_game(name) do child_spec = %{ id: GameServer, start: {GameServer, :start_link, [name]}, restart: :temporary } DynamicSupervisor.start_child(__MODULE__, child_spec) end def game_exists?(game_name) do case Registry.lookup(:game_server_registry, game_name) do [] -> false _ -> true end end end
  57. defmodule GameEngine.GameSupervisor do alias GameEngine.GameServer use DynamicSupervisor def start_link(_) do

    DynamicSupervisor.start_link(__MODULE__, nil, name: __MODULE__) end def init(_) do DynamicSupervisor.init(strategy: :one_for_one) end def create_game(name) do child_spec = %{ id: GameServer, start: {GameServer, :start_link, [name]}, restart: :temporary } DynamicSupervisor.start_child(__MODULE__, child_spec) end def game_exists?(game_name) do case Registry.lookup(:game_server_registry, game_name) do [] -> false _ -> true end end end
  58. defmodule GameEngine.GameServer do ... @impl true def handle_call({:leave, symbol}, _from,

    state) do new_state = state |> Game.remove_player(symbol) |> Game.reset_board() if Game.without_players?(new_state) do {:stop, :normal, new_state} else {:reply, {:ok, game_state}, new_state} end end ... end
  59. defmodule GameEngine.GameServer do ... @impl true def handle_cast({:leave, symbol}, state)

    do new_state = state |> Game.remove_player(symbol) |> Game.reset_board() if Game.without_players?(new_state) do {:stop, :normal, new_state} else {:noreply, new_state} end end ... end
  60. defmodule GameEngine.GameSupervisor do alias GameEngine.GameServer use DynamicSupervisor def start_link(_) do

    DynamicSupervisor.start_link(__MODULE__, nil, name: __MODULE__) end def init(_) do DynamicSupervisor.init(strategy: :one_for_one) end def create_game(name) do child_spec = %{ id: GameServer, start: {GameServer, :start_link, [name]}, restart: :temporary } DynamicSupervisor.start_child(__MODULE__, child_spec) end def game_exists?(game_name) do case Registry.lookup(:game_server_registry, game_name) do [] -> false _ -> true end end end
  61. defmodule GameEngine.Application do alias GameEngine.{GameRegistry, GameSupervisor} use Application def start(_type,

    _args) do import Supervisor.Spec, warn: false children = [ GameRegistry, GameSupervisor ] opts = [strategy: :one_for_one, name: GameEngine.Supervisor] Supervisor.start_link(children, opts) end end
  62. defmodule GameEngine.Application do alias GameEngine.{GameRegistry, GameSupervisor} use Application def start(_type,

    _args) do import Supervisor.Spec, warn: false children = [ GameRegistry, GameSupervisor ] opts = [strategy: :one_for_one, name: GameEngine.Supervisor] Supervisor.start_link(children, opts) end end
  63. defmodule GameEngine.Application do alias GameEngine.{GameRegistry, GameSupervisor} use Application def start(_type,

    _args) do import Supervisor.Spec, warn: false children = [ GameRegistry, GameSupervisor ] opts = [strategy: :one_for_one, name: GameEngine.Supervisor] Supervisor.start_link(children, opts) end end
  64. defmodule GameEngine do @moduledoc """ Expose all public API's for

    projects that depend on `GameEngine`. """ alias GameEngine.{GameServer, GameSupervisor} defdelegate join_player(game, player), to: GameServer defdelegate put_player_symbol(game, symbol, pos), to: GameServer defdelegate new_round(game), to: GameServer defdelegate leave(game, symbol), to: GameServer def find_or_create_game(game_name) do if GameSupervisor.game_exists?(game_name) do game_name else {:ok, _pid} = GameSupervisor.create_game(game_name) game_name end end end
  65. defmodule GameEngine do @moduledoc """ Expose all public API's for

    projects that depend on `GameEngine`. """ alias GameEngine.{GameServer, GameSupervisor} defdelegate join_player(game, player), to: GameServer defdelegate put_player_symbol(game, symbol, pos), to: GameServer defdelegate new_round(game), to: GameServer defdelegate leave(game, symbol), to: GameServer def find_or_create_game(game_name) do if GameSupervisor.game_exists?(game_name) do game_name else {:ok, _pid} = GameSupervisor.create_game(game_name) game_name end end end
  66. defmodule GameEngine do @moduledoc """ Expose all public API's for

    projects that depend on `GameEngine`. """ alias GameEngine.{GameServer, GameSupervisor} defdelegate join_player(game, player), to: GameServer defdelegate put_player_symbol(game, symbol, pos), to: GameServer defdelegate new_round(game), to: GameServer defdelegate leave(game, symbol), to: GameServer def find_or_create_game(game_name) do if GameSupervisor.game_exists?(game_name) do game_name else {:ok, _pid} = GameSupervisor.create_game(game_name) game_name end end end
  67. defmodule GameUi.MixProject do ... defp deps do [ {:phoenix, "~>

    1.4.0"}, {:phoenix_pubsub, "~> 1.1"}, {:phoenix_html, "~> 2.11"}, {:phoenix_live_reload, "~> 1.2", only: :dev}, {:gettext, "~> 0.11"}, {:jason, "~> 1.0"}, {:plug_cowboy, "~> 2.0"}, {:game_engine, in_umbrella: true} ] end end