10:aa2a22dbe1e7
Anton Shestakov <engored@ya.ru>, Wed, 26 Feb 2014 01:46:12 +0900
Use lists:keymember for testing if player has already made his choice.

next change 11:9dd5bb0a4c0c
previous change 9:4b4d65b99174

rps.erl

Permissions: -rw-r--r--

Other formats: Feeds:
-module(rps).
-import(rps3, [get_rules/0, beats/1]).
-export([
go/0,
winner/1,
lobby/0, counter/0, printer/0, room/1,
fool/0, copycat/0, gambler/0]).
-define(BOTS, [fool, copycat, gambler]).
% 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(get_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, [])),
register(counter, spawn(rps, counter, [])),
register(printer, spawn(rps, printer, [])),
[spawn(rps, Bot, []) || Bot <- ?BOTS].
lobby() ->
lobby([]).
lobby(Players) when length(Players) =:= length(?BOTS) ->
Room = spawn(rps, room, [Players]),
lists:foreach(fun(Player) -> Player ! {room, Room} end, Players),
lobby([]);
lobby(Players) ->
receive
{join, Who} ->
lobby([Who|Players])
end.
counter() ->
counter(0, 0, dict:new()).
counter(Plays, Draws, Wins) ->
receive
{draw, _} ->
counter(Plays + 1, Draws + 1, Wins);
{winner, {_, Winner}} ->
counter(Plays + 1, Draws, dict:update_counter(Winner, 1, Wins));
{sendstats, Pid} ->
Pid ! {stats, {plays, Plays, draws, Draws, wins, dict:to_list(Wins)}},
counter(Plays, Draws, Wins)
end.
printer() ->
receive
{stats, Stats} ->
io:format("Stats: ~w.~n", [Stats])
after 1000 ->
counter ! {sendstats, self()}
end,
printer().
room(Players) ->
lists:foreach(fun(Player) -> Player ! start end, Players),
room(Players, []).
room(Players, Choices) when length(Players) =:= length(Choices) ->
Winner = winner(Choices),
Msg = if
Winner =:= undefined ->
{draw, Choices};
true ->
{winner, Winner}
end,
counter ! Msg,
lists:foreach(fun(Player) -> Player ! Msg end, Players),
room(Players);
room(Players, Choices) ->
receive
{Object, Who} ->
ObjectIsOk = lists:any(fun(X) -> X =:= Object end, get_rules()),
ChoiceMade = lists:keymember(Who, 2, 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(get_rules())), get_rules()),
Room ! {Choice, self()},
fool(Room);
{winner, _} ->
fool(Room)
end.
copycat() ->
lobby ! {join, self()},
copycat(joined).
copycat(joined) ->
receive
{room, Room} ->
copycat(Room, hd(get_rules()))
end.
copycat(Room, Choice) ->
receive
start ->
Room ! {Choice, self()},
copycat(Room, Choice);
{winner, {NewChoice, _}} ->
copycat(Room, NewChoice)
end.
gambler() ->
lobby ! {join, self()},
gambler(joined).
gambler(joined) ->
receive
{room, Room} ->
Wins = dict:from_list([{C, 0} || C <- get_rules()]),
gambler(Room, Wins)
end.
gambler(Room, Wins) ->
receive
start ->
F = fun({_, A}, {_, B}) -> A =< B end,
{Choice, _} = hd(lists:sort(F, dict:to_list(Wins))),
Room ! {Choice, self()},
gambler(Room, Wins);
{winner, {Choice, _}} ->
gambler(Room, dict:update_counter(Choice, 1, Wins))
end.