Hi all, pretty new to the forum although I’ve been lead here countless times already when googling answers Thanks all who contribute here.
I’m new to Elixir and using Phoenix (and Vuejs) to create a turn-based TC game . Clients communicate through sockets, game states are stored in a GenServer (which will probably also persist the data to Postgres at some point since I already use PG to hold accounts and etc).
My question though is related to mapping the game state. When a game starts a map container with general info and each players info is generated. I then communicate this game state through sockets to each client - but since part of the map should be invisible to the opposing player I need to clear that out from each broadcast (so player 1 gets specific data from player 2 removed from the message, and vice-versa).
First I tried doing this:
def clean_player(:player_2 , state) do
put_in(state, ["player_2", :deck], false)
put_in(state, ["player_2", :decklist], false)
put_in(state, ["player_2", :grimoire], false)
put_in(state, ["player_2", :sideboard], false)
state
end
(I eventually |> piped state into each put_in but then just to make sure I wrote it like that)
If I IO.puts state["player_2"][:deck]
I will see the key, but the put_in doesn’t really do anything. It doesn’t raise an error but it also leaves the map unchanged. So I switched to creating a new hash map, using info from the existing map and setting the keys I want “invisible” to whatever, like so:
%{
players: state[:players],
status: state[:status],
player_1: state["player_1"],
player_2: %{
username: state["player_2"][:username],
deck: false,
decklist: false,
life: 20,
aether: state["player_2"][:aether],
grimoire: false,
graveyard: state["player_2"][:graveyard],
play: state["player_2"][:play],
exile: state["player_2"][:exile],
sideboard: false,
time: state["player_2"][:time],
last_activity: state["player_2"][:last_activity],
player: state["player_2"][:player],
on_play: state["player_2"][:on_play],
played_flux: state["player_2"][:played_flux],
roll: state["player_2"][:roll],
id: state["player_2"][:id]
},
you: "player_1",
opponent: "player_2",
messages: state[:messages]
}
And this works, but my question is why can’t I replace the values with put_in
? Is it because I’m using a string based key and atoms together? I tried searching but couldn’t find anything mentioning this in the docs, I would expect it to work. Or is it something silly on my end?
If it is because of the atoms do you have any idea of how I could write:
|> Map.put(“player_#{number}”, %{
username: player.username,
…
…
})
So to have the map key dynamically created but as an atom? Probably the way I’m doing it is very ruby like…
Lastly, is there any real drawback to using maps with atom keys in such a situation? Like, imagining I had thousands of players at the same time, would this matter?
Thanks