# 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.