Skip to content

Instantly share code, notes, and snippets.

@tecnowilliam
Created May 29, 2020 00:49
Show Gist options
  • Select an option

  • Save tecnowilliam/e3e0d662011cc1bc637d63dcb7dd5040 to your computer and use it in GitHub Desktop.

Select an option

Save tecnowilliam/e3e0d662011cc1bc637d63dcb7dd5040 to your computer and use it in GitHub Desktop.
% Compile:
% c(rpss).
-module(rpss).
-author("William Vargas").
-version("1.0").
-export([
play/1,
echo/1,
play_two/3,
rock/1,
no_repeat/1,
enum/1,
cycle/1,
rand/1,
val/1,
tournament/2,
least_frequent/1,
most_frequent/1,
rand_play/1,
best_play/2
]).
-type move() :: rock | paper | scissors.
%
% play one strategy against another, for N moves.
%
-spec play_two(function(),function(),integer()) -> ok | error.
play_two(StrategyL,StrategyR,N) ->
play_two(StrategyL,StrategyR,[],[],N).
% tail recursive loop for play_two/3
% 0 case computes the result of the tournament
% FOR YOU TO DEFINE
% REPLACE THE dummy DEFINITIONS
-spec play_two(function(),function(),[move()],[move()],integer()) -> ok | error.
play_two(_,_,PlaysL,PlaysR,0) ->
io:format("PlayerLeft: ~p~n",[PlaysL]),
io:format("PlayerRight: ~p~n",[PlaysR]),
io:format("Winner: ~p~n",[lists:sum(lists:map(fun outcome/1,lists:zipwith(fun result/2, PlaysL, PlaysR)))]);
play_two(StrategyL,StrategyR,PlaysL,PlaysR,N) ->
play_two(StrategyL, StrategyR,[StrategyL(PlaysR) | PlaysL],[StrategyR(PlaysL) | PlaysR], N-1).
%
% interactively play against a strategy, provided as argument.
%
-spec play(function()) -> ok | error.
play(Strategy) ->
io:format("Rock - paper - scissors~n"),
io:format("Play one of rock, paper, scissors, ...~n"),
io:format("... r, p, s, stop, followed by '.'~n"),
play(Strategy,[]).
% tail recursive loop for play/1
-spec play(function(),[move()]) -> ok | error.
play(Strategy,Moves) ->
{ok,P} = io:read("Play: "),
Play = expand(P),
case Play of
stop ->
io:format("Stopped~n");
_ ->
Move = Strategy(Moves),
Result = result(Play,Move),
% io:format("Play: ~p~n",[Play]),
io:format("Move: ~p~n",[Move]),
io:format("Result: ~p~n",[Result]),
play(Strategy,[Play|Moves])
end.
%
% auxiliary functions
%
% transform shorthand atoms to expanded form
-spec expand(atom()) -> atom().
expand(r) -> rock;
expand(p) -> paper;
expand(s) -> scissors;
expand(X) -> X.
% result of one set of plays
-spec result(atom(),atom()) -> atom().
result(rock,rock) -> draw;
result(rock,paper) -> lose;
result(rock,scissors) -> win;
result(paper,rock) -> win;
result(paper,paper) -> draw;
result(paper,scissors) -> lose;
result(scissors,rock) -> lose;
result(scissors,paper) -> win;
result(scissors,scissors) -> draw.
% result of a tournament
-spec tournament([move()],[move()]) -> list().
tournament(PlaysL,PlaysR) ->
lists:sum(
lists:map(fun outcome/1,
lists:zipwith(fun result/2,PlaysL,PlaysR))).
-spec outcome(atom()) -> integer().
outcome(win) -> 1;
outcome(lose) -> -1;
outcome(draw) -> 0.
% transform 0, 1, 2 to rock, paper, scissors and vice versa.
-spec enum(integer()) -> move().
enum(0) ->
rock;
enum(1) ->
paper;
enum(2) ->
scissors.
-spec val(move()) -> integer().
val(rock) ->
0;
val(paper) ->
1;
val(scissors) ->
2.
% give the play which the argument beats.
-spec beats(move()) -> move().
beats(rock) ->
scissors;
beats(paper) ->
rock;
beats(scissors) ->
paper.
-spec defeat(move()) -> move().
defeat(Move) ->
beats(beats(Move)).
-spec count_moves([move()],tuple()) -> tuple().
count_moves([],Moves) ->
Moves;
count_moves([X|Xs],{R,P,S}) ->
case X of
rock -> count_moves(Xs,{R+1,P,S});
paper -> count_moves(Xs,{R,P+1,S});
_ -> count_moves(Xs,{R,P,S+1})
end.
%
% strategies.
%
-spec echo([move()]) -> move().
echo([]) ->
paper;
echo([Last|_]) ->
Last.
-spec rock(move()) -> rock.
rock(_) ->
rock.
% FOR YOU TO DEFINE
% REPLACE THE dummy DEFINITIONS
-spec no_repeat([move()]) -> move().
no_repeat([]) ->
paper;
no_repeat([Move|_]) ->
defeat(Move).
-spec rand(move()) -> move().
rand(_) ->
enum(rand:uniform(3) - 1).
-spec cycle([move()]) -> move().
cycle(Xs) ->
enum(length(Xs) rem 3).
-spec least_frequent([move()]) -> move().
least_frequent(Xs) ->
{R,P,S} = count_moves(Xs,{0,0,0}),
case {R, P, S} of
_ when R =< P andalso R =< S -> defeat(rock);
_ when P =< R andalso P =< S -> defeat(paper);
_ -> defeat(scissors)
end.
-spec most_frequent([move()]) -> move().
most_frequent(Xs) ->
{R,P,S} = count_moves(Xs,{0,0,0}),
case {R, P, S} of
_ when R >= P andalso R >= S -> defeat(rock);
_ when P >= R andalso P >= S -> defeat(paper);
_ -> defeat(scissors)
end.
-spec rand_play([function()]) -> error_empty | move().
rand_play([]) ->
error_empty;
rand_play(Sx) ->
play(lists:nth(rand:uniform(length(Sx)),Sx)).
-spec best_play([function()],[move()]) -> error_empty | move().
best_play([],[]) ->
error_empty;
best_play([],_) ->
[];
best_play([S|Sx],P) ->
[best_play(S,P,{0,0,0}),best_play(Sx,P)].
-spec best_play([function()],[move()],tuple()) -> list().
best_play(S,[],{W,D,L}) ->
{S,{"Win",W},{"Draw",D},{"Lose",L}};
best_play(S,[P|Px],{W,D,L}) ->
case result(P,S(Px)) of
win -> best_play(S,Px,{W+1,D,L});
draw -> best_play(S,Px,{W,D+1,L});
_ -> best_play(S,Px,{W,D,L+1})
end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment