We can't find the internet
Attempting to reconnect
Something went wrong!
Hang in there while we get back on track
First we need to have the application set up the names of the Supervisors that we will call by name later in the MultiPoker game. These will be responsible for managing the Rooms and the Players.
Be sure to add something like this to your application.ex
def start(_type, _args) do
children = [
...
{Registry, keys: :unique, name: GameSite.MultiPoker.RoomRegistry},
{DynamicSupervisor, strategy: :one_for_one, name: GameSite.MultiPoker.RoomSupervisor},
...
GameSiteWeb.Endpoint
]
...
end
Okay with that out of the way we can work on the creation and naming of the rooms.
defmodule GameSite.MultiPoker do
alias GameSite.MultiPoker.{Room, Player}
@room_supervisor GameSite.MultiPoker.RoomSupervisor
@registry GameSite.MultiPoker.RoomRegistry
def create_room(user_id) do
room_id = Ecto.UUID.generate()
player = Player.new(user_id)
case start_room(room_id, player) do
{:ok, _pid} -> {:ok, room_id}
{:error, reason} -> {:error, reason}
end
end
def get_room_pid(room_id) do
case Registry.lookup(@registry, room_id) do
[{pid, _}] -> {:ok, pid}
[] -> :error
end
end
def get_room(room_id) do
case get_room_pid(room_id) do
{:ok, pid} -> {:ok, Room.get_state(pid)}
:error -> :error
end
end
defp start_room(room_id, host_player) do
spec = %{
id: room_id,
start: {Room, :start_link, [host_player, [room_id: room_id]]}
}
DynamicSupervisor.start_child(@room_supervisor, spec)
end
end
Before I go onto the testing I want to note that currently we are not naming the Rooms when we create the GenServer so we need to go back to the Room context and make sure that we have a way of associating that with the correct Supervisor.
def start_link(host, opts \\ []) do
room_id = Keyword.fetch!(opts, :room_id)
GenServer.start_link(
__MODULE__,
{host, opts},
name: via(room_id)
)
end
defp via(room_id) do
{:via, Registry, {GameSite.MultiPoker.RoomRegistry, room_id}}
end
Okay lets go into some testing!!!
# First let's start an iex session with a Erlang node name
iex --sname game_site -S mix phx.server
# Then in an other terminal run this too connect
iex --sname debug --remsh game_site@$(hostname)
# This should get us up and running
Okay so we have a terminal running and one connected let’s start the testing
iex(game_site@DESKTOP-ANBE9HK)1> Node.self()
:"game_site@DESKTOP-ANBE9HK"
iex(game_site@DESKTOP-ANBE9HK)2> {:ok, room_id} = GameSite.MultiPoker.create_room(123)
{:ok, "b3ef3892-5143-4b90-a323-99d63ced50a6"}
iex(game_site@DESKTOP-ANBE9HK)3> {:ok, pid} = GameSite.MultiPoker.get_room_pid(room_id)
{:ok, #PID<0.959.0>}
iex(game_site@DESKTOP-ANBE9HK)4> {:ok, room} = GameSite.MultiPoker.get_room(room_id)
{:ok,
%GameSite.MultiPoker.Room{
players: %{
123 => %GameSite.MultiPoker.Player{
player_id: 123,
ready?: false,
chips: 1000,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
}
},
room_id: "b3ef3892-5143-4b90-a323-99d63ced50a6",
room_status: :waiting,
host_id: 123,
full: false
}}
iex(game_site@DESKTOP-ANBE9HK)5> room.room_id
"b3ef3892-5143-4b90-a323-99d63ced50a6"
iex(game_site@DESKTOP-ANBE9HK)6> room.host_id
123
iex(game_site@DESKTOP-ANBE9HK)7> room.players
%{
123 => %GameSite.MultiPoker.Player{
player_id: 123,
ready?: false,
chips: 1000,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
}
}
iex(game_site@DESKTOP-ANBE9HK)8> room.players[123]
%GameSite.MultiPoker.Player{
player_id: 123,
ready?: false,
chips: 1000,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
}
iex(game_site@DESKTOP-ANBE9HK)9> player2 = GameSite.MultiPoker.Player.new(456)
%GameSite.MultiPoker.Player{
player_id: 456,
ready?: false,
chips: 1000,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
}
iex(game_site@DESKTOP-ANBE9HK)10> GameSite.MultiPoker.Room.add_player(pid, player2)
:ok
iex(game_site@DESKTOP-ANBE9HK)11> {:ok, room} = GameSite.MultiPoker.get_room(room_id)
{:ok,
%GameSite.MultiPoker.Room{
players: %{
123 => %GameSite.MultiPoker.Player{
player_id: 123,
ready?: false,
chips: 1000,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
},
456 => %GameSite.MultiPoker.Player{
player_id: 456,
ready?: false,
chips: 1000,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
}
},
room_id: "b3ef3892-5143-4b90-a323-99d63ced50a6",
room_status: :waiting,
host_id: 123,
full: false
}}
iex(game_site@DESKTOP-ANBE9HK)12> room.players
%{
123 => %GameSite.MultiPoker.Player{
player_id: 123,
ready?: false,
chips: 1000,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
},
456 => %GameSite.MultiPoker.Player{
player_id: 456,
ready?: false,
chips: 1000,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
}
}
iex(game_site@DESKTOP-ANBE9HK)13> GameSite.MultiPoker.Room.remove_player(pid, player2)
:ok
iex(game_site@DESKTOP-ANBE9HK)14> {:ok, room} = GameSite.MultiPoker.get_room(room_id)
{:ok,
%GameSite.MultiPoker.Room{
players: %{
123 => %GameSite.MultiPoker.Player{
player_id: 123,
ready?: false,
chips: 1000,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
}
},
room_id: "b3ef3892-5143-4b90-a323-99d63ced50a6",
room_status: :waiting,
host_id: 123,
full: false
}}
iex(game_site@DESKTOP-ANBE9HK)15> room.players
%{
123 => %GameSite.MultiPoker.Player{
player_id: 123,
ready?: false,
chips: 1000,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
}
}
iex(game_site@DESKTOP-ANBE9HK)16> GameSite.MultiPoker.Room.update_status(pid, :ready)
:ok
iex(game_site@DESKTOP-ANBE9HK)17> {:ok, room} = GameSite.MultiPoker.get_room(room_id)
{:ok,
%GameSite.MultiPoker.Room{
players: %{
123 => %GameSite.MultiPoker.Player{
player_id: 123,
ready?: false,
chips: 1000,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
}
},
room_id: "b3ef3892-5143-4b90-a323-99d63ced50a6",
room_status: :ready,
host_id: 123,
full: false
}}
iex(game_site@DESKTOP-ANBE9HK)18> room.room_status
:ready
Let’s go over what we did there:
We first stared a Server with a named node.
Then we used an other terminal to connect to that node.
Once we were in the iex session we:
Create a room
Find the pid
Read room state
Then inspect
Verify the host player is stored correctly
Test adding a player manually
Create another player:
Then add them to the room:
Then re-read state:
Test removing a player
Test room status update
You should be able to work with all of this to see what other things you can do. Let’s look into changing a player within a room. Right now the only way to do this would be to remove the player from with remove_player the room and then add them back into the room with add_player. So let’s take a minute to add that to the GenServer
def handle_cast({:update_player, player_id, opts}, %__MODULE__{players: players} = state) do
new_players =
case Map.fetch(players, player_id) do
{:ok, player} ->
updated_player = Player.change(player, opts)
Map.put(players, player_id, updated_player)
:error ->
players
end
{:noreply, %__MODULE__{state | players: new_players}}
end
def update_player(pid, player_id, opts) do
GenServer.cast(pid, {:update_player, player_id, opts})
end
Quick note on this I choose to only pass the player.id so that we can keep as little being passed around. Some might argue that you should pass the entire struct but you might not need to as you only need the player.id to removed the player as that is what we have them stored under. Okay so let’s test it.
iex(game_site@DESKTOP-ANBE9HK)24> GameSite.MultiPoker.Room.update_player(pid, 123, %{chips: 200, ready?: false})
:ok
iex(game_site@DESKTOP-ANBE9HK)25> GameSite.MultiPoker.Room.get_state(pid)
%GameSite.MultiPoker.Room{
players: %{
123 => %GameSite.MultiPoker.Player{
player_id: 123,
ready?: false,
chips: 200,
current_bet: 0,
folded?: false,
seat_position: nil,
hand: [],
connected?: true
}
},
room_id: "b3ef3892-5143-4b90-a323-99d63ced50a6",
room_status: :ready,
host_id: 123,
full: false
}
I would take some time now and add some test for the current modules that you have. Things like did the Player get created correctly? Did the Player change as it should. For the Room create a setup that creates the Room and then test it was created with the right values, then change and see what happens. Lastly for the MultiPoker make sure that you can create the room with the create_room/1 and then test to see that you get the right errors for bad params.