Skip to content

Instantly share code, notes, and snippets.

@sathish316
Last active September 14, 2015 10:05
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sathish316/2fb6833065500e80277a to your computer and use it in GitHub Desktop.
Save sathish316/2fb6833065500e80277a to your computer and use it in GitHub Desktop.
Snakes and Ladder - Elixir Game server
defmodule GameServer do
use GenServer
def start do
initial_state = {:players, [], :positions, Map.new, :snakes_and_ladders, [
{:ladder, 5, 15}, {:ladder, 10, 22}, {:ladder, 25, 45}, {:snake, 35, 15}, {:snake, 65, 55}]}
GenServer.start_link(__MODULE__, initial_state, name: __MODULE__)
end
def join(player), do: GenServer.cast(__MODULE__, {:join, player})
def play, do: GenServer.call(__MODULE__, {:play})
def display, do: GenServer.call(__MODULE__, {:display})
def shutdown, do: GenServer.cast(__MODULE__, {:bye})
def handle_cast({:join, player}, state) do
{:players, players, :positions, positions, :snakes_and_ladders, snakes_and_ladders} = state
{:noreply, {:players, [player | players], :positions, Map.put(positions, player, 1), :snakes_and_ladders, snakes_and_ladders}}
end
def handle_call({:play}, _from, state) do
{:players, players, :positions, positions, :snakes_and_ladders, snakes_and_ladders} = state
[current_player | others] = players
dice_value = :random.uniform(6)
new_position = next_position(positions[current_player] + dice_value, snakes_and_ladders)
if new_position < 100 do
new_positions = Map.put(positions, current_player, new_position)
new_players = others ++ [current_player]
{:reply, {current_player, new_position}, {:players, new_players, :positions, new_positions, :snakes_and_ladders, snakes_and_ladders}}
else
{:reply, {current_player, :winner}, state}
end
end
def handle_call({:display}, _from, state) do
{:players, _, :positions, positions, :snakes_and_ladders, _} = state
{:reply, positions, state}
end
def handle_cast({:bye}, state), do: {:stop, :shutdown, state}
defp next_position(pos, snakes_and_ladders) do
handle_elem(Enum.filter(snakes_and_ladders, fn({_type, from, _to}) -> from == pos end), pos)
end
defp handle_elem([], pos), do: pos
defp handle_elem([{:snake, _, to}], _), do: to
defp handle_elem([{:ladder, _, to}], _), do: to
end
@sathish316
Copy link
Author

For playing game from iex:

c("snakes_and_ladders.ex")
GameServer.start
GameServer.join("a")
GameServer.join("b")
GameServer.join("c")
GameServer.play
GameServer.play
GameServer.play
GameServer.display
for i <- 1..50, do: GameServer.play
GameServer.display

@avinasha
Copy link

@sathish316 Any particular reason you are using a tuple for the initial state and not a map?

%{players: [], positions: %{}, snakes_and_ladders: [ {:ladder, 5, 15}, {:ladder, 10, 22}, {:ladder, 25, 45}, {:snake, 35, 15}, {:snake, 65, 55}]}

@sathish316
Copy link
Author

@avinasha: No specific reason. I was following the convention of using {:ok , foo} tuples in elixir. Destructuring code could become a lot simpler if i use map.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment