2:ecb57261bc30
Anton Shestakov <engored@ya.ru>, Sun, 23 Feb 2014 00:19:13 +0900
Intermediate bot state: "joined" the lobby, but not in a room yet.

next change 3:8bbf038c39cc
previous change 1:f44d2a7c91f4

rps.erl

Permissions: -rw-r--r--

Other formats: Feeds:
-module(rps).
-export([lobby/0, room/1, beats/1, winner/1, go/0, fool/0]).
-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() ->
register(lobby, spawn(rps, lobby, [])),
[spawn(rps, fool, []) || _ <- 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 ! {join, self()},
fool(joined).
fool(joined) ->
receive
{room, Room} ->
random:seed(now()),
fool(Room)
end;
fool(Room) ->
receive
start ->
Choice = lists:nth(random:uniform(length(?RULES)), ?RULES),
Room ! {Choice, self()},
fool(Room);
{winner, _} ->
fool(Room)
end.