   defp make_nonsense_msg(token), do: "BLABLA;#{token}"
   defp make_announcement_msg(token, d1, d2), do: "ANNOUNCE;#{d1},#{d2};#{token}"
   defp make_see_msg(token), do: "SEE;#{token}"
-  
-  defp do_see(socket, port, player, sockets) do
-    socket
+
+  defp want_to_see(game, playerno) do
+    player = game[:players][playerno]
+    player[:socket]
       |> receive_message()
       |> check_and_gettoken(:yourturn)
       |> make_see_msg()
-      |> send_to_server(socket, port)
-    check_broadcast_message(sockets, "PLAYER WANTS TO SEE;#{player}\n")
-  end
-  
-  defp do_roll(socket, port, player, sockets) do
-    socket
+      |> send_to_server(player[:socket], player[:port])
+    check_broadcast_message(game[:sockets], "PLAYER WANTS TO SEE;#{player[:name]}\n")
+    game
+  end
+
+  defp roll(game, playerno) do
+    player = game[:players][playerno]
+    player[:socket]
       |> receive_message()
       |> check_and_gettoken(:yourturn)
       |> make_roll_msg()
-      |> send_to_server(socket, port)
-    check_broadcast_message(sockets, "PLAYER ROLLS;#{player}\n")
-  end
-
-  defp do_announcement(socket, port, player, d1, d2, sockets) do
-    socket
+      |> send_to_server(player[:socket], player[:port])
+    check_broadcast_message(game[:sockets], "PLAYER ROLLS;#{player[:name]}\n")
+    game
+  end
+
+  defp announce(game, playerno, {d1, d2}) do
+    player = game[:players][playerno]
+    player[:socket]
       |> receive_message()
       |> check_and_gettoken(:rolled)
       |> make_announcement_msg(d1,d2)
-      |> send_to_server(socket, port)
-    check_broadcast_message(sockets, "ANNOUNCED;#{player};#{d1},#{d2}\n")
+      |> send_to_server(player[:socket], player[:port])
+    check_broadcast_message(game[:sockets], "ANNOUNCED;#{player[:name]};#{d1},#{d2}\n")
+    game
+  end
+
+  defp inject_dice(game, {d1, d2}) do
+    MiaServer.Game.testing_inject_dice(d1,d2)
+    game
+  end
+
+  defp check_yourturn(game, playerno) do
+    game[:players][playerno][:socket]
+      |> receive_message()
+      |> check_and_gettoken(:yourturn)
+    game
   end
 
   test "First player receives Your Turn" do
-    {startmsg, sockets, ports} = setup_game()
-    {turn, _players, [socket | _], _ports} = extract_player_seq(startmsg, sockets, ports)
-    assert turn == 1
-    socket |> receive_message() |> check_and_gettoken(:yourturn)
+    game = setup_game()
+    assert game[:turn] == 1
+    game[:players][1][:socket] |> receive_message() |> check_and_gettoken(:yourturn)
   end
 
   test "First player rolls and receives dice" do
-    {startmsg, sockets, ports} = setup_game()
-    {1, [player | _], [socket | _], [port | _]} = extract_player_seq(startmsg, sockets, ports)
-    do_roll(socket, port, player, sockets)
-    socket |> receive_message() |> check_and_gettoken(:rolled)
+    game = setup_game()
+    game |> roll(1)
+    game[:players][1][:socket] |> receive_message() |> check_and_gettoken(:rolled)
   end
 
   test "First player does nothing" do
-    {startmsg, sockets, ports} = setup_game()
-    {1, [player | _], [socket | _], _} = extract_player_seq(startmsg, sockets, ports)
-    receive_message(socket)
+    game = setup_game()
+    receive_message(game[:players][1][:socket])
     Process.sleep(@timeout)
-    check_player_lost_aftermath(player, sockets, "DID NOT TAKE TURN")
+    player_lost(game, 1, "DID NOT TAKE TURN")
   end
 
   test "Player sends invalid command" do
-    {startmsg, sockets, ports} = setup_game()
-    {1, [player | _], [socket | _], [port | _]} = extract_player_seq(startmsg, sockets, ports)
-    socket
+    game = setup_game()
+    player = game[:players][1]
+    player[:socket]
       |> receive_message()
       |> check_and_gettoken(:yourturn)
       |> make_nonsense_msg()
-      |> send_to_server(socket, port)
-    check_player_lost_aftermath(player, sockets, "INVALID TURN")
+      |> send_to_server(player[:socket], player[:port])
+    player_lost(game, 1, "INVALID TURN")
   end
 
   test "Player rolls but fails to announce" do
-    {startmsg, sockets, ports} = setup_game()
-    {1, [player | _], [socket | _], [port | _]} = extract_player_seq(startmsg, sockets, ports)
-    do_roll(socket, port, player, sockets)
-    receive_message(socket)
+    game = setup_game()
+    game |> roll(1)
+    receive_message(game[:players][1][:socket])
     Process.sleep(@timeout)
-    check_player_lost_aftermath(player, sockets, "DID NOT ANNOUNCE")
+    player_lost(game, 1, "DID NOT ANNOUNCE")
   end
 
   test "Game round with consecutive announcements" do
-    {startmsg, sockets, ports} = setup_game()
-    {1, [player1, player2 | _], [socket1, socket2 | _], [port1, port2 | _]} = extract_player_seq(startmsg, sockets, ports)
-    MiaServer.Game.testing_inject_dice(3,1)
-    do_roll(socket1, port1, player1, sockets)
-    do_announcement(socket1, port1, player1, 3, 1, sockets)
-    # Second players turn
-    MiaServer.Game.testing_inject_dice(3,2)
-    do_roll(socket2, port2, player2, sockets)
-    do_announcement(socket2, port2, player2, 4, 1, sockets)
-    # Again first players turn
-    socket1 |> receive_message() |> check_and_gettoken(:yourturn)
+    setup_game()
+      |> inject_dice({3,1})
+      |> roll(1)
+      |> announce(1, {3,1})
+      |> inject_dice({3,2})
+      |> roll(2)
+      |> announce(2, {4,1})
+      |> check_yourturn(1)
   end
 
   test "Player announces lower dice" do
-    {startmsg, sockets, ports} = setup_game()
-    {1, [player1, player2 | _], [socket1, socket2 | _], [port1, port2 | _]} = extract_player_seq(startmsg, sockets, ports)
-    MiaServer.Game.testing_inject_dice(6,1)
-    do_roll(socket1, port1, player1, sockets)
-    do_announcement(socket1, port1, player1, 6, 1, sockets)
-    # Second players turn
-    MiaServer.Game.testing_inject_dice(3,2)
-    do_roll(socket2, port2, player2, sockets)
-    do_announcement(socket2, port2, player2, 5, 1, sockets)
-    check_player_lost_aftermath(player2, sockets, "ANNOUNCED LOSING DICE")
+    setup_game()
+      |> inject_dice({6,1})
+      |> roll(1)
+      |> announce(1, {6,1})
+      |> inject_dice({3,2})
+      |> roll(2)
+      |> announce(2, {5,1})
+      |> player_lost(2, "ANNOUNCED LOSING DICE")
   end
 
   test "Player announces invalid MIA" do
-    {startmsg, sockets, ports} = setup_game()
-    {1, [player1 | _], [socket1 | _], [port1 | _]} = extract_player_seq(startmsg, sockets, ports)
-    MiaServer.Game.testing_inject_dice(6,1)
-    do_roll(socket1, port1, player1, sockets)
-    do_announcement(socket1, port1, player1, 2, 1, sockets)
-    check_player_lost_aftermath(player1, sockets, "LIED ABOUT MIA")
+    setup_game()
+      |> inject_dice({6,1})
+      |> roll(1)
+      |> announce(1, {2,1})
+      |> player_lost(1, "LIED ABOUT MIA")
   end
 
   test "Player announces valid MIA" do
-    {startmsg, sockets, ports} = setup_game()
-    {1, [player1, player2 | _], [socket1 | _], [port1 | _]} = extract_player_seq(startmsg, sockets, ports)
-    MiaServer.Game.testing_inject_dice(2,1)
-    do_roll(socket1, port1, player1, sockets)
-    do_announcement(socket1, port1, player1, 2, 1, sockets)
-    check_player_lost_aftermath(player2, sockets, "MIA")
-  end
-  
+    setup_game()
+      |> inject_dice({2,1})
+      |> roll(1)
+      |> announce(1, {2,1})
+      |> player_lost(2, "MIA")
+  end
+
   test "Player wants to see, but no previous roll was made" do
-    {startmsg, sockets, ports} = setup_game()
-    {1, [player | _], [socket | _], [port | _]} = extract_player_seq(startmsg, sockets, ports)
-    do_see(socket, port, player, sockets)
-    check_player_lost_aftermath(player, sockets, "SEE BEFORE FIRST ROLL")
+    setup_game()
+      |> want_to_see(1)
+      |> player_lost(1, "SEE BEFORE FIRST ROLL")
   end
 
   test "Player wants to see, but roll was correctly annnounced" do
-    {startmsg, sockets, ports} = setup_game()
-    {1, [player1, player2 | _], [socket1, socket2 | _], [port1, port2 | _]} = extract_player_seq(startmsg, sockets, ports)
-    MiaServer.Game.testing_inject_dice(6,1)
-    do_roll(socket1, port1, player1, sockets)
-    do_announcement(socket1, port1, player1, 5, 1, sockets)
-    # Second players turn
-    do_see(socket2, port2, player2, sockets)
-    check_player_lost_aftermath(player2, sockets, "SEE FAILED")
+    setup_game()
+      |> inject_dice({6,1})
+      |> roll(1)
+      |> announce(1, {5,1})
+      |> want_to_see(2)
+      |> player_lost(2, "SEE FAILED")
   end
 
   test "Player wants to see, and previous player bluffed" do
-    {startmsg, sockets, ports} = setup_game()
-    {1, [player1, player2 | _], [socket1, socket2 | _], [port1, port2 | _]} = extract_player_seq(startmsg, sockets, ports)
-    MiaServer.Game.testing_inject_dice(5,1)
-    do_roll(socket1, port1, player1, sockets)
-    do_announcement(socket1, port1, player1, 6, 1, sockets)
-    # Second players turn
-    do_see(socket2, port2, player2, sockets)
-    check_player_lost_aftermath(player1, sockets, "CAUGHT BLUFFING")
-  end
-
+    setup_game()
+      |> inject_dice({5,1})
+      |> roll(1)
+      |> announce(1, {6,1})
+      |> want_to_see(2)
+      |> player_lost(1, "CAUGHT BLUFFING")
+  end
 
 end

    receive_message(socket1)
    receive_message(socket2)
    start = receive_message(socket3)
    {start, [socket1, socket2, socket3], [port1, port2, port3]}
  end

  defp extract_player_seq(startmsg, sockets, ports) do
    [_, turn, seq] = Regex.run(~r/ROUND STARTED;(.*);(.*)\n/, startmsg)
    playerseq = seq |> String.split(",")
    socketseq = playerseq |> Enum.map(fn "player" <> n -> Enum.at(sockets, String.to_integer(n)-1) end)
    portseq = playerseq |> Enum.map(fn "player" <> n -> Enum.at(ports, String.to_integer(n)-1) end)
    {String.to_integer(turn), playerseq, socketseq, portseq}
  end

  defp check_broadcast_message(sockets, msg) do
    for s <- sockets do
      assert {:ok, {_ip, _port, m}} = :gen_udp.recv(s, 0, @timeout)
      assert msg == m
    end
  end

  defp check_player_lost_aftermath(player, sockets, reason) do
    check_broadcast_message(sockets, "PLAYER LOST;#{player};#{reason}\n")
    scoremsg = case player do
      "player1" -> "SCORE;player1:0,player2:1\n"
      "player2" -> "SCORE;player1:1,player2:0\n"
    end
    check_broadcast_message(sockets, scoremsg)
    invites = for s <- sockets do
      {:ok, {_ip, _port, invitation}} = :gen_udp.recv(s, 0, @timeout)
      invitation
    end

    assert message =~ regex
    [_, token] = Regex.run(regex, message)
    token
  end

  defp extract_player_seq(game, startmsg) do
    [_, turn, seq] = Regex.run(~r/ROUND STARTED;(.*);(.*)\n/, startmsg)

    players = seq
      |> String.split(",")
      |> Enum.with_index
      |> Enum.map(fn {"player" <> n,i} ->
                    {i+1, %{:name => "player"<>n,
                            :socket => Enum.at(game[:sockets], String.to_integer(n)-1),
                            :port => Enum.at(game[:ports], String.to_integer(n)-1)}
                    }
                  end)
      |> Enum.into(%{})

    %{game | :turn => String.to_integer(turn), :players => players}
  end

  defp setup_game() do
