Store and Retrieve the Game State
Learn how to keep track of the game state.
We'll cover the following
We want to store the full state for each game in the :game_state
table whenever it changes. We register each game process by the name of the first player, so the name makes a great key to store the state under.
Changes in the Game
module
For game processes, some states will change whenever there is a successful reply, either in the game itself or in the state machine data. Luckily, we wrote a single function in the Game
module to handle successful replies— reply_success/2
. A call to :ets.insert/2
with the name :player1
as the key and the full game state as the value is all we need:
defp reply_success(state_data, reply) do
:ets.insert(:game_state, {state_data.player1.name, state_data})
{:reply, reply, state_data, @timeout}
end
Any time we start or restart a process, GenServer
triggers the init/1
callback. That makes init/1
a good place to check the :game_state
table for any state stored under the first player’s name.
If :ets.lookup/2
returns an empty list, we generate fresh state the way init/1
had done before. If :ets.lookup/2
returns some state, we use that instead.
We add a new private function that returns the state of a new game given the first player’s name:
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
Then, we can use that new function in init/1
:
def init(name) do
state_data =
case :ets.lookup(:game_state, name) do
[] -> fresh_state(name)
[{_key, state}] -> state
end
:ets.insert(:game_state, {name, state_data})
{:ok, state_data, @timeout}
end
Get hands-on with 1400+ tech skills courses.