# HG changeset patch
# User Anton Shestakov <engored@ya.ru>
# Date 1393081468 -32400
# Node ID 58a061003687bbe3d48af4dc15fbe983a9f60260

Working thing.

diff -r 000000000000 -r 58a061003687 rps.erl
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rps.erl	Sun Feb 23 00:04:28 2014 +0900
@@ -0,0 +1,108 @@
+-module(rps).
+-export([lobby/0, room/1, beats/1, winner/1, go/0, fool/1]).
+
+-define(RULES, [rock, paper, scissors]).
+
+beats(C) ->
+    beats(C, ?RULES).
+
+beats(C, [C|Tail]) ->
+    lists:last(Tail);
+
+beats(C, [B,C|_]) ->
+    B;
+
+beats(C, [_|T]) ->
+    beats(C, T).
+
+% winner for 3 players is:
+% rock, rock, rock      -> undefined
+% rock, paper, scissors -> undefined
+% rock, paper, paper    -> undefined
+% rock, rock, paper     -> {paper, Who}
+
+winner(Choices) when length(Choices) > 1 ->
+    CSet = sets:from_list([C || {C, _} <- Choices]),
+    RSet = sets:from_list(?RULES),
+    Absents = sets:subtract(RSet, CSet),
+    case sets:size(Absents) of
+        1 ->
+            Absent = hd(sets:to_list(Absents)),
+            Unbeaten = beats(Absent),
+            Winners = [{C, Who} || {C, Who} <- Choices, C =:= Unbeaten],
+            case length(Winners) of
+                1 -> hd(Winners);
+                _ -> undefined
+            end;
+        _ -> undefined
+    end.
+
+go() ->
+    Lobby = spawn(rps, lobby, []),
+    [spawn(rps, fool, [Lobby]) || _ <- lists:seq(1, 3)].
+    
+lobby() ->
+    lobby([]).
+
+lobby(Players) when length(Players) =:= 3 ->
+    Room = spawn(rps, room, [Players]),
+    lists:foreach(fun(Player) -> Player ! {room, Room} end, Players),
+    lobby([]);
+
+lobby(Players) ->
+    receive
+        {join, Who} ->
+            lobby([Who|Players])
+    end.
+
+room(Players) ->
+    lists:foreach(fun(Player) -> Player ! start end, Players),
+    room(Players, []).
+
+room(Players, Choices) when length(Players) =:= length(Choices) ->
+    Best = winner(Choices),
+    Msg = if
+              Best =:= undefined ->
+                  io:format("draw: ~w.~n", [Choices]),
+                  draw;
+              true ->
+                  io:format("the winner is ~w.~n", [Best]),
+                  {winner, Best}
+          end,
+    lists:foreach(fun(Player) -> Player ! Msg end, Players),
+    room(Players);
+
+room(Players, Choices) ->
+    receive
+        {Object, Who} ->
+            ObjectIsOk = lists:any(fun(X) -> X =:= Object end, ?RULES),
+            ChoiceMade = lists:any(fun({_, Player}) -> Player =:= Who end, Choices),
+            case ObjectIsOk andalso not ChoiceMade of
+                true ->
+                    room(Players, [{Object, Who}|Choices]);
+                false -> 
+                    io:format("~w picks ~w, not allowed.~n", [Who, Object]),
+                    room(Players, Choices)
+            end
+    end.
+
+fool(Lobby) ->
+    Lobby ! {join, self()},
+    fool(Lobby, undefined).
+
+fool(Lobby, undefined) ->
+    receive
+        {room, Room} ->
+            random:seed(now()),
+            fool(Lobby, Room)
+    end;
+
+fool(Lobby, Room) ->
+    receive
+        start ->
+            Choice = lists:nth(random:uniform(length(?RULES)), ?RULES),
+            Room ! {Choice, self()},
+            fool(Lobby, Room);
+        {winner, _} ->
+            fool(Lobby, Room)
+    end.