From 2fc26764f623255199d61a2bf20a6c1ded845b15 Mon Sep 17 00:00:00 2001 From: Rowa Date: Tue, 5 Nov 2024 00:16:41 +0300 Subject: [PATCH 1/2] stores and retrieves game state in ets --- lib/battle_ship/application.ex | 1 + lib/battle_ship/game.ex | 27 +++++++++++++++++++++++---- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/lib/battle_ship/application.ex b/lib/battle_ship/application.ex index 108746f..7c6fc28 100644 --- a/lib/battle_ship/application.ex +++ b/lib/battle_ship/application.ex @@ -16,6 +16,7 @@ defmodule BattleShip.Application do # See https://hexdocs.pm/elixir/Supervisor.html # for other strategies and supported options + :ets.new(:game_state, [:public, :named_table]) opts = [strategy: :one_for_one, name: BattleShip.Supervisor] Supervisor.start_link(children, opts) end diff --git a/lib/battle_ship/game.ex b/lib/battle_ship/game.ex index 94b66e1..9ad61b5 100644 --- a/lib/battle_ship/game.ex +++ b/lib/battle_ship/game.ex @@ -39,9 +39,8 @@ defmodule BattleShip.Game do rules: struct() }} def init(name) do - player1 = %{name: name, board: Board.new(), guesses: Guesses.new()} - player2 = %{name: nil, board: Board.new(), guesses: Guesses.new()} - {:ok, %{player1: player1, player2: player2, rules: %Rules{}}, @timeout} + send(self(), {:set_state, name}) + {:ok, fresh_state(name)} end @spec add_player(pid(), binary()) :: :error | {:reply, :ok, %{}} @@ -141,11 +140,25 @@ defmodule BattleShip.Game do {:stop, {:shutdown, :timeout}, state_data} end + def handle_info({:set_state, name}, _state_data) do + state_data = + case :ets.lookup(:game_state, name) do + [] -> fresh_state(name) + [{_key, state}] -> state + end + + :ets.insert(:game_state, {name, state_data}) + {:noreply, state_data, @timeout} + end + defp update_player2_name(state_data, name), do: put_in(state_data.player2.name, name) defp update_rules(state_data, rules), do: %{state_data | rules: rules} - defp reply_success(state_data, reply), do: {:reply, reply, state_data, @timeout} + defp reply_success(state_data, reply) do + :ets.insert(:game_state, {state_data.player1.name, state_data}) + {:reply, reply, state_data, @timeout} + end defp update_board(state_data, player, board), do: Map.update!(state_data, player, fn player -> %{player | board: board} end) @@ -160,4 +173,10 @@ defmodule BattleShip.Game do Guesses.add(guesses, hit_or_miss, coordinate) end) end + + defp fresh_state(name) do + player1 = %{name: name, board: Board.new(), guesses: Guesses.new()} + player2 = %{name: nil, board: Board.new(), guesses: Guesses.new()} + %{player1: player1, player2: player2, rules: %Rules{}} + end end From dd786b9c44ff6680a8acbd65d1292a5736a83f12 Mon Sep 17 00:00:00 2001 From: Rowa Date: Tue, 5 Nov 2024 00:25:48 +0300 Subject: [PATCH 2/2] cleans up after a game --- lib/battle_ship/game.ex | 7 +++++++ lib/battle_ship/game_supervisor.ex | 1 + 2 files changed, 8 insertions(+) diff --git a/lib/battle_ship/game.ex b/lib/battle_ship/game.ex index 9ad61b5..9a303a2 100644 --- a/lib/battle_ship/game.ex +++ b/lib/battle_ship/game.ex @@ -60,6 +60,13 @@ defmodule BattleShip.Game do def guess_coordinate(game, player, row, col) when player in @players, do: GenServer.call(game, {:guess_coordinate, player, row, col}) + def terminate({:shutdown, :timeout}, state_data) do + :ets.delete(:game_state, state_data.player1.name) + :ok + end + + def terminate(_reason, _state), do: :ok + def handle_call({:guess_coordinate, player, row, col}, _from, state_data) do opponent = opponent(player) opponent_board = player_board(state_data, opponent) diff --git a/lib/battle_ship/game_supervisor.ex b/lib/battle_ship/game_supervisor.ex index ce5f661..b98e324 100644 --- a/lib/battle_ship/game_supervisor.ex +++ b/lib/battle_ship/game_supervisor.ex @@ -12,6 +12,7 @@ defmodule BattleShip.GameSupervisor do def start_game(name), do: Supervisor.start_child(GameSupervisor, [name]) def stop_game(name) do + :ets.delete(:game_state, name) Supervisor.terminate_child(GameSupervisor, pid_from_name(name)) end