Last active
March 22, 2017 17:06
-
-
Save 7-fl/82d0324f83c9cc9b412bc7e970104de0 to your computer and use it in GitHub Desktop.
Finished! + After the fact, I was able to implement more comprehensive testing.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -module(rps). | |
| -compile(export_all). | |
| -include_lib("eunit/include/eunit.hrl"). | |
| % | |
| % play one strategy against another, for N moves. | |
| % | |
| play_two(S1, S2, N) -> | |
| play_two(S1, S2, N, [], [], 0). %Added 0 variable to sum the score. | |
| % tail recursive loop for play_two/3 | |
| % 0 case computes the result of the tournament | |
| % FOR YOU TO DEFINE | |
| % REPLACE THE dummy DEFINITIONS | |
| play_two(_, _, 0, _, _, Score) -> | |
| print_tournament_winner(Score); | |
| play_two(S1, S2, N, Ls, Rs, Score) -> | |
| PlayL = S1(Rs), | |
| PlayR = S2(Ls), | |
| Result = result(PlayL, PlayR), | |
| print_round_winner(Result), | |
| play_two(S1, S2, N-1, [PlayL|Ls], [PlayR|Rs], Score+outcome(Result) ). | |
| print_round_winner(Result) -> | |
| Results = case Result of | |
| win -> [won, lost]; | |
| draw -> [draw, draw]; | |
| lose -> [lost, won] | |
| end, | |
| io:format("StrategyL: ~5w, StrategyR: ~5w~n", Results). | |
| print_tournament_winner(Score) -> | |
| Winner = if | |
| Score>0 -> "StrategyL"; | |
| Score<0 -> "StrategyR"; | |
| Score=:=0 -> "--Draw--" | |
| end, | |
| io:format("Tournament Winner:~n\t~s (Score: ~w)~n", [Winner, abs(Score)]). | |
| % | |
| % interactively play against a strategy, provided as argument. | |
| % | |
| 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,[], 0). | |
| % tail recursive loop for play/1 | |
| play(Strategy, Moves, Score) -> | |
| {ok,P} = io:read("Play: "), | |
| Play = expand(P), | |
| case Play of | |
| stop -> | |
| Winner = if | |
| Score>0 -> "You!"; | |
| Score<0 -> "The Strategy"; | |
| Score=:=0 -> "--Draw--" | |
| end, | |
| io:format("Tournament winner: ~s (Score: ~w)~n", [Winner, abs(Score)]), | |
| io:format("Stopped~n"); | |
| _ -> | |
| Result = result(Play,Strategy(Moves)), | |
| io:format("Result: ~p~n",[Result]), | |
| play(Strategy,[Play|Moves], Score+outcome(Result)) | |
| end. | |
| % | |
| % auxiliary functions | |
| % | |
| % transform shorthand atoms to expanded form | |
| expand(r) -> rock; | |
| expand(p) -> paper; | |
| expand(s) -> scissors; | |
| expand(X) -> X. | |
| % result of one set of plays | |
| 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 | |
| tournament(PlaysL,PlaysR) -> | |
| lists:sum( | |
| lists:map(fun outcome/1, | |
| lists:zipwith(fun result/2,PlaysL,PlaysR))). | |
| outcome(win) -> 1; | |
| outcome(lose) -> -1; | |
| outcome(draw) -> 0. | |
| % transform 0, 1, 2 to rock, paper, scissors and vice versa. | |
| enum(0) -> | |
| rock; | |
| enum(1) -> | |
| paper; | |
| enum(2) -> | |
| scissors. | |
| val(rock) -> | |
| 0; | |
| val(paper) -> | |
| 1; | |
| val(scissors) -> | |
| 2. | |
| % give the play which the argument beats. | |
| beats(rock) -> | |
| paper; | |
| beats(paper) -> | |
| scissors; | |
| beats(scissors) -> | |
| rock. | |
| % | |
| % strategies. | |
| % | |
| echo([]) -> | |
| paper; | |
| echo([Last|_]) -> | |
| Last. | |
| rock(_) -> | |
| rock. | |
| % FOR YOU TO DEFINE | |
| % REPLACE THE dummy DEFINITIONS | |
| %--------- | |
| plays() -> | |
| [rock, paper, scissors]. | |
| %--------- | |
| no_repeat_test() -> | |
| %Test empty list of Opponent's plays: | |
| OppPlays1 = [], | |
| Responses1 = plays(), | |
| loop(10, Responses1, fun rps:no_repeat/2, OppPlays1), | |
| %Test non-empty list of Oppenents Plays: | |
| OppPlays2 = [rock], %Opp => Opponent | |
| Responses2 = others( my_hd(OppPlays2) ), | |
| loop(10, Responses2, fun rps:no_repeat/2, OppPlays2), | |
| OppPlays3 = [paper, scissors, paper], | |
| Responses3 = others( my_hd(OppPlays3) ), | |
| loop(10, Responses3, fun rps:no_repeat/2, OppPlays3), | |
| all_tests_passed. | |
| %Replaced the following to make testing easier: | |
| %no_repeat([]) -> %First play, no list of opponent's plays. | |
| % rand([]); | |
| %no_repeat([Play|_]) -> | |
| % Others = others(Play), | |
| % rand_from(Others, fun random:uniform/1). | |
| no_repeat(OppPlays) -> | |
| no_repeat(OppPlays, fun random:uniform/1). %Allows me to write tests for no_repeat/2, | |
| %by passing in a determinstic RandFunc of my | |
| no_repeat([], RandFunc) -> %own, e.g. fun(_Len) -> 1 end, in place of | |
| rand_from(plays(), RandFunc); %random:uniform/1 | |
| no_repeat([Play|_], RandFunc) -> | |
| Others = others(Play), | |
| rand_from(Others, RandFunc). | |
| %--------- | |
| %loop_test() -> | |
| %loop(0, a, b, c), | |
| %loop(3, [rock, paper], fun rps:const/2, [rock, paper, paper, scissors]), | |
| %all_tests_passed. | |
| loop(0, _, _, _) -> | |
| ok; | |
| loop(N, Responses, Strategy, OppPlays) when N >=0 -> | |
| RandNum = random:uniform( len(Responses) ), %Get random index value in Responses list. | |
| TestRandFunc = fun(_X) -> RandNum end, %Create a determinstic RandFunc. | |
| Expected = get_elmt(RandNum, Responses), % Expected Play corresponding to RandFunc. | |
| Expected = Strategy(OppPlays, TestRandFunc), %See if the Strategy returns Expected. | |
| loop(N-1, Responses, Strategy, OppPlays). | |
| %--------- | |
| others_test() -> | |
| [scissors, paper] = others(rock), | |
| [scissors, rock] = others(paper), | |
| [paper, rock] = others(scissors), | |
| all_tests_passed. | |
| others(Play) -> | |
| others(Play, plays(), []). | |
| others(_Play, [], Others) -> | |
| Others; | |
| others(Play, [Play|Ps], Others)-> | |
| others(Play, Ps, Others); | |
| others(Play, [P|Ps], Others) -> | |
| others(Play, Ps, [P|Others]). | |
| %------------- | |
| %rand_from() is a helper function that returns a random element from a list. | |
| rand_from_test() -> | |
| RandFunc1 = fun(_X) -> 1 end, | |
| RandFunc2 = fun(_X) -> 2 end, | |
| L = [a, b, c], | |
| a = rand_from(L, RandFunc1), | |
| b = rand_from(L, RandFunc2), | |
| all_tests_passed. | |
| rand_from(L) when length(L)>0 -> | |
| rand_from(L, fun random:uniform/1). %This allows me to write tests for rand_from/2 | |
| %by passing in a determinstic RandFunc of my | |
| rand_from(L, RandFunc) -> %own, e.g. fun(_Len) -> 1 end, in place of | |
| RandNum = RandFunc( len(L) ), %%random:uniform/1 | |
| get_elmt(RandNum, L). | |
| %-------------- | |
| const_test() -> | |
| rock = const([]), | |
| rock = const([paper, rock, paper]), | |
| all_tests_passed. | |
| const(OppPlays) -> | |
| const(OppPlays, fun(_X) -> 1 end). %Necessary to give all the Strategies the | |
| %same interface for testing. | |
| const(OppPlays, RandFunc) -> | |
| Strat = rand_from([fun rps:rock/1], RandFunc), | |
| Strat(OppPlays). | |
| %--------- | |
| %% Can't test this: | |
| %% | |
| %% rand(Ps) -> | |
| %% Plays = plays(), | |
| %% Rand = random:uniform(len(Plays)), | |
| %% get_elmt(Rand, Plays). | |
| rand_test() -> | |
| %loop(N, Responses, Strategy, OppPlays) | |
| Responses = plays(), | |
| OppPlays1 = [], | |
| loop(10, Responses, fun rps:rand/2, OppPlays1), | |
| OppPlays2 = [paper, rock, rock, scissors], %Irrelevant. | |
| loop(10, Responses, fun rps:rand/2, OppPlays2), | |
| all_tests_passed. | |
| rand(OppPlays) -> | |
| rand(OppPlays, fun random:uniform/1). %I implemented rand/2, so that I could test | |
| %rand/2 by passing in a deterministic RandFunc. | |
| rand(_, RandFunc) -> %Also, handles empty list of opponent plays. | |
| rand_from(plays(), RandFunc). | |
| %------------ | |
| cycle_test() -> | |
| rock = cycle([]), | |
| paper = cycle([rock]), | |
| scissors = cycle([paper]), | |
| rock = cycle([scissors]), | |
| all_tests_passed. | |
| %Algorithm: in the plays() list return the play after the index | |
| %position of the opponent's play: | |
| cycle(OppPlays) -> | |
| cycle(OppPlays, fun random:uniform/1). %Necessary to give all Strategies the same | |
| %two arg interface for testing. | |
| cycle(OppPlays, RandFunc) when is_function(RandFunc) -> | |
| cycle(OppPlays, plays()); %Get rid of the RandFunc. | |
| cycle([], [Play|_Plays]) -> %No opponent plays, response is first play in plays(), i.e. rock. | |
| Play; | |
| cycle([P|_Ps], [P|[]]) -> %Opponent's play matches last one in plays(), response is first play. | |
| [Response|_] = plays(), | |
| Response; | |
| cycle([P|_Ps], [P|Plays]) -> %Response is next play after opponent's play. | |
| [Response|_] = Plays, | |
| Response; | |
| cycle(Ps, [_|Plays]) -> | |
| cycle(Ps, Plays). | |
| %-------------- | |
| least_freq_test() -> | |
| %loop(N, Responses, Strategy, OppPlays) | |
| OppPlays = [], | |
| Responses4 = lists:map(fun rps:beats/1, plays() ), | |
| loop(10, Responses4, fun rps:least_freq/2, OppPlays), | |
| OppPlays1 = [rock, scissors, paper, rock, scissors], | |
| Responses1 = [beats(paper)], %paper is least frequent in OppPlays1 | |
| loop(10, Responses1, fun rps:least_freq/2, OppPlays1), | |
| OppPlays2 = [rock, paper, paper, scissors, scissors], | |
| Responses2 = [beats(rock)], % rock is least frequent in OppPlays2. | |
| loop(10, Responses2, fun rps:least_freq/2, OppPlays2), | |
| OppPlays3 = [scissors], | |
| Responses3 = [beats(rock), beats(paper)], | |
| % OppPlays = [scissors] => paper, rock will have freqs of 0 | |
| % least_freq calls get_freqs(), which returns the order: scissors, paper, rock. | |
| % best frequencies will reverse those again => rock, paper | |
| loop(10, Responses3, fun rps:least_freq/2, OppPlays3), | |
| all_tests_passed. | |
| least_freq(OppPlays) -> | |
| least_freq(OppPlays, fun random:uniform/1). %This allows me to test least_freq/2 | |
| least_freq([], RandFunc) -> | |
| %rand([], RandFunc) %Removed => couldn't test. | |
| Responses = lists:map( | |
| fun rps:beats/1, | |
| plays() | |
| ), | |
| rand_from(Responses, RandFunc); | |
| least_freq(OppPlays, RandFunc) -> | |
| MinFunc = fun(X, Y) -> %Compare the simplicity of an if-stmt to the | |
| if %nested case-stmts that do the same thing below. | |
| X<Y -> repl; | |
| X=:=Y -> add; | |
| X>Y -> skip | |
| end | |
| end, | |
| MinFreqs = best_freqs( get_freqs(OppPlays), MinFunc ), %There could be more than one... | |
| {Play, _Freq} = rand_from(MinFreqs, RandFunc), %so pick a random min frequency. | |
| beats(Play). | |
| %-------------- | |
| get_freqs_test() -> | |
| [{scissors,0}, {paper, 0}, {rock, 0}] = get_freqs([]), | |
| [{scissors,1}, {paper, 1}, {rock, 1}] = get_freqs([rock, paper, scissors]), | |
| [{scissors,0}, {paper, 2}, {rock, 2}] = get_freqs([rock, paper, rock, paper]), | |
| [{scissors,2}, {paper, 0}, {rock, 1}] = get_freqs([scissors, scissors, rock]), | |
| [{scissors,0}, {paper, 2}, {rock, 1}] = get_freqs([paper, rock, paper]), | |
| all_tests_passed. | |
| get_freqs(OppPlays) -> | |
| get_freqs(plays(), [], OppPlays). | |
| get_freqs([], Counts, _OppPlays) -> | |
| Counts; | |
| get_freqs([P|Ps], Counts, OppPlays) -> | |
| Count = count(P, OppPlays), | |
| get_freqs(Ps, [{P, Count} | Counts], OppPlays). | |
| %---------- | |
| best_freqs_test() -> | |
| %Collect minimum frequencies: | |
| MinFunc = fun(X, Y) -> | |
| case X<Y of | |
| true -> repl; | |
| false -> case X>Y of | |
| true -> skip; | |
| false -> add | |
| end | |
| end | |
| end, | |
| %Collect maximum frequencies: | |
| MaxFunc = fun(X, Y) -> | |
| case X<Y of | |
| true -> skip; | |
| false -> case X>Y of | |
| true -> repl; | |
| false -> add | |
| end | |
| end | |
| end, | |
| [{b,1}] = best_freqs([{a,2},{b,1},{c,3}], MinFunc), | |
| [{c,1}, {b,1}] = best_freqs([{a,2},{b,1},{c,1}], MinFunc), | |
| [{c,1}, {b,1}, {a,1}] = best_freqs([{a,1},{b,1},{c,1}], MinFunc), | |
| [{c,3}] = best_freqs([{a,2},{b,1},{c,3}], MaxFunc), | |
| [{c,2}, {a,2}] = best_freqs([{a,2},{b,1},{c,2}], MaxFunc), | |
| [{c,1}, {b,1}, {a,1}] = best_freqs([{a,1},{b,1},{c,1}], MaxFunc), | |
| all_tests_passed. | |
| best_freqs([X|Xs], CompareCounts) -> | |
| best_freqs(Xs, CompareCounts, [X]). %Start off by choosing the first element | |
| %as the one with the "best" count. | |
| best_freqs([], _CompareCounts, Bests) -> | |
| Bests; | |
| best_freqs([ {_Name, Count}=X | Xs], CompareCounts, [ {_BestName, BestCount} | _]=Bests) -> | |
| case CompareCounts(Count, BestCount) of | |
| repl -> best_freqs(Xs, CompareCounts, [X]); | |
| add -> best_freqs(Xs, CompareCounts, [X|Bests]); | |
| skip -> best_freqs(Xs, CompareCounts, Bests) | |
| end. | |
| %----------------- | |
| most_freq_test() -> | |
| OppPlays1 = [rock, scissors, paper, rock, scissors, rock], | |
| Responses1 = [beats(rock)], %Most freq in OppPlays1 is rock. | |
| loop(10, Responses1, fun rps:most_freq/2, OppPlays1), | |
| OppPlays2 = [rock, paper, paper, scissors], | |
| Responses2 = [beats(paper)], %Most freq in OppPlays2 is paper. | |
| loop(10, Responses2, fun rps:most_freq/2, OppPlays2), | |
| OppPlays3 = [scissors], %=> paper, rock will have freqs of 0. | |
| Responses3 = [beats(scissors)], %Most freq in OppPlays3 is scissors. | |
| loop(10, Responses3, fun rps:most_freq/2, OppPlays3), | |
| OppPlays4 = [], % most freq => rock, paper, scissors | |
| %get_freqs => scissors, paper, rock | |
| %best_freqs => rock, paper, scissors | |
| Responses4 = [beats(rock), beats(paper), beats(scissors)], %Must be in right order! | |
| loop(3, Responses4, fun rps:most_freq/2, OppPlays4), | |
| all_tests_passed. | |
| most_freq(OppPlays) -> | |
| most_freq(OppPlays, fun random:uniform/1). | |
| most_freq([], RandFunc) -> | |
| %rand([], RandFunc). %Removed => couldn't test. | |
| Responses = lists:map( | |
| fun rps:beats/1, | |
| plays() | |
| ), | |
| rand_from(Responses, RandFunc); | |
| most_freq(OppPlays, RandFunc) -> | |
| MaxFunc = fun(X, Y) -> | |
| if | |
| X>Y -> repl; | |
| X=:=Y -> add; | |
| X < Y -> skip | |
| end | |
| end, | |
| MaxFreqs = best_freqs( get_freqs(OppPlays), MaxFunc ), | |
| {Play, _Count} = rand_from(MaxFreqs, RandFunc), | |
| beats(Play). | |
| %------------ | |
| apply_rand_strat_test() -> | |
| RandFunc1 = fun(_X) -> 1 end, | |
| RandFunc2 = fun(_X) -> 2 end, | |
| RandFunc3 = fun(_X) -> 3 end, | |
| Strats = [fun rps:no_repeat/1, fun rps:cycle/1, fun rps:least_freq/1], | |
| Plays = [rock, paper], | |
| %Need to specify module name for pattern match to work: | |
| Strat1 = fun rps:no_repeat/1, | |
| Strat1 = apply_rand_strat(Strats, Plays, RandFunc1), | |
| Strat2 = fun rps:cycle/1, | |
| Strat2 = apply_rand_strat(Strats, Plays, RandFunc2), | |
| Strat3 = fun rps:least_freq/1, | |
| Strat3 = apply_rand_strat(Strats, Plays, RandFunc3), | |
| all_tests_passed. | |
| apply_rand_strat(Ss, Ps) when length(Ss)>0 -> | |
| apply_rand_strat(Ss, Ps, fun random:uniform/1). | |
| apply_rand_strat(Ss, _Ps, RandFunc) -> | |
| rand_from(Ss, RandFunc). | |
| %------------- | |
| apply_best_strat_test() -> | |
| Strats1 = [fun rps:cycle/2, fun rps:most_freq/2, fun rps:const/2], | |
| RandFunc1 = fun(_X) -> 1 end, | |
| Plays1 = [rock, paper, rock], | |
| %cycle([]) => rock, rock v. (last)rock => 0 | |
| %cycle[[rock]) => paper, paper v. paper => 0 | |
| %cycle([paper, rock]) => scissors, scissors v. rock => -1 | |
| % | |
| %m_f([]) => All are "best" freqs, and choosing with RandFunc1 => beats(rock), | |
| % paper v. (last)rock => +1 | |
| %m_f([rock]) => beats(rock), paper v. paper => 0 | |
| %m_f([paper, rock]) => get_freqs() is always in the same order(the reverse | |
| % of plays(): scissors, paper, rock; then best_freqs() | |
| % reverses its results, so most freq in this case choosing | |
| % with RandFunc1 will be rock => paper, paper v. rock => +1 | |
| % | |
| %const([]) => rock, rock v. (last)rock => 0 | |
| %cons([rock]) => rock, rock v. paper => -1 | |
| %const([paper, rock]) => rock, rock v. rock => 0 | |
| Expected1 = rps:most_freq(Plays1, RandFunc1), | |
| Expected1 = apply_best_strat(Strats1, Plays1, RandFunc1), | |
| Plays2 = [scissors, paper, rock], | |
| %cycle([]) -> rock, rock v. last(rock) => 0 | |
| %cycle([rock]) -> rock, rock v. paper => -1 | |
| %cycle([paper,rock]) -> scissors v. scissors => 0 | |
| % | |
| %m_f([]) => based on RandFunc1 => beat(rock), paper v. rock => +1 | |
| %m_f([rock]) => beat(rock), paper v. paper => 0 | |
| %m_f([paper, rock]) => beat(rock) => paper, paper v. scissors => -1 | |
| % | |
| %const([]) => rock, rock v. rock => 0 | |
| %const([rock]) => rock, rock v. paper => -1 | |
| %const([paper, rock]) => rock, rock v. scissors => +1 | |
| %Ss get reversed by apply_best_strategy() before picking best strategy. | |
| %Based on RandFunc1 first S in reversed best Ss will be best strat. | |
| Expected2 = rps:const(Plays2, RandFunc1), | |
| Expected2 = apply_best_strat(Strats1, Plays2, RandFunc1), | |
| Strats3 = [fun rps:rand/2, fun rps:no_repeat/2, fun rps:least_freq/2], | |
| Plays3 = [paper, paper, paper], | |
| %rand([]) => rock, rock v. paper => -1 | |
| %rand([paper]) => rock, rock v. paper => -1 | |
| %rand([paper, paper]) => rock, rock v paper => -1 | |
| % | |
| %no_repeat([]) -> rock, rock v. paper => -1 | |
| %no_repeat([paper]) => scissors, scissors v. paper => 1 | |
| %no_repeat([paper, paper]) => scissors, scissors v. paper => 1 | |
| % | |
| %l_f([]) => beat(rock) => paper, paper v. paper => 0 | |
| %l_f([paper]) => beat(rock) => paper, paper v. paper => 0 | |
| %l_f([paper, paper]) => beat(rock) => paper, paper v. paper => 0 | |
| Expected3 = rps:no_repeat(Plays3, RandFunc1), | |
| Expected3 = apply_best_strat(Strats3, Plays3, RandFunc1), | |
| all_tests_passed. | |
| % Variables: | |
| % | |
| % Ss => Strategies | |
| % Ps => Opponent's Plays | |
| % Score => {StrategyFunc, Score} | |
| % | |
| apply_best_strat(Ss, []) when length(Ss)>0 -> | |
| apply_best_strat(Ss, [], fun random:uniform/1). | |
| apply_best_strat(Ss, [], RandFunc) when length(Ss)>0 -> | |
| Strat = rand_from(Ss, RandFunc), | |
| Strat([]); | |
| apply_best_strat(Ss, Ps, RandFunc) when length(Ss)>0 -> | |
| Scores = apply_best_strat(Ss, Ps, RandFunc, []), | |
| MaxFunc = fun(X, Y) -> | |
| if | |
| X>Y -> repl; | |
| X=:=Y -> add; | |
| X<Y -> skip | |
| end | |
| end, | |
| {BestStrat, _Score} = rand_from( %Pick first "best" strategy. No! Let's get a random one. | |
| best_freqs(Scores, MaxFunc), | |
| RandFunc | |
| ), | |
| BestStrat(Ps, RandFunc). | |
| apply_best_strat([], _Ps, _RandFunc, Scores) -> | |
| Scores; | |
| apply_best_strat([S|Ss], Ps, RandFunc, Scores) -> | |
| Score = backTest(S, Ps, RandFunc), %Funky function name so that eunit doesn't consider it a test. | |
| apply_best_strat(Ss, Ps, RandFunc, [Score|Scores]). | |
| backTest_test() -> | |
| %Test const/2 | |
| % const() => rock | |
| RandFunc1 = fun(_X) -> 1 end, | |
| Score1 = {fun rps:const/2, -1}, | |
| Score1 = backTest(fun rps:const/2,[paper], RandFunc1), | |
| Score2 = {fun rps:const/2, +1}, | |
| Score2 = backTest(fun rps:const/2, [scissors], RandFunc1), | |
| Score3 = {fun rps:const/2, -2}, | |
| Score3 = backTest(fun rps:const/2, [paper, rock, paper], RandFunc1), | |
| Score4 = {fun rps:const/2, 0}, | |
| Score4 = backTest(fun rps:const/2, [rock, scissors, paper], RandFunc1), | |
| Score5 = {fun rps:const/2, +2}, | |
| Score5 = backTest(fun rps:const/2, [scissors, rock, scissors], RandFunc1), | |
| %Test least_freq/2: | |
| History1 = [rock, paper], | |
| Plays1 = [rock], | |
| %least_freq(History1) => scissors, so Response would be beats(scissors) => rock, | |
| %which draws with the rock in Plays1, thus Score = {least_freq, 0} | |
| Score6 = {fun rps:least_freq/2, 0}, | |
| Score6 = backTest(fun rps:least_freq/2, Plays1, RandFunc1, History1, []), | |
| History2 = [rock, paper], | |
| Plays2 = [scissors], | |
| Score7 = {fun rps:least_freq/2, 1}, | |
| Score7 = backTest(fun rps:least_freq/2, Plays2, RandFunc1, History2, []), | |
| History3 = [rock, paper], | |
| Plays3 = [paper, paper], | |
| Score8 = {fun rps:least_freq/2, -2}, | |
| Score8 = backTest(fun rps:least_freq/2, Plays3, RandFunc1, History3, []), | |
| History4 = [], | |
| Plays4 = [rock, paper], | |
| %% l_f([]) => beat(rock) => paper, paper v. paper => 0 | |
| %% l_f([paper]) => paper, paper v. rock => +1 | |
| %% l_f([rock, paper]) -> ends | |
| %% Total => 0 | |
| Score9 = {fun rps:least_freq/2, 1}, | |
| Score9 = backTest(fun rps:least_freq/2, reverse(Plays4), RandFunc1, History4, []), | |
| %Test most_freq/2: | |
| History5 = [], | |
| Plays5 = [paper, rock, scissors], | |
| %% m_f([]) => beat(rock), paper v. scissors => -1 | |
| %% m_f([scissors]) => beat(scissors) => rock, rock v. rock => 0 | |
| %% m_f([rock, scissors]) => beat(rock) => paper v. paper => 0 | |
| %% m_f([rock, paper]) -> ends | |
| %% Total => -1 | |
| Score10 = {fun rps:most_freq/2, -1}, | |
| Score10 = backTest(fun rps:most_freq/2, reverse(Plays5), RandFunc1, History5, []), | |
| %Test cycle/2: | |
| History6 = [], | |
| Plays6 = [paper, rock, scissors], | |
| %% cycle([]) => rock, rock v. scissors => +1 | |
| %% cycle([scissors]) => rock, rock v. rock => 0 | |
| %% cycle([rock, scissors]) => paper v. paper => 0 | |
| %% cycle([rock, paper]) -> ends | |
| %% Total => +1 | |
| Score11 = {fun rps:cycle/2, +1}, | |
| Score11 = backTest(fun rps:cycle/2, reverse(Plays6), RandFunc1, History6, []), | |
| %Test rand/2: | |
| %rand([]) => rock, rock v. scissors => +1 | |
| %rand([scissors]) => rock, rock v. rock => 0 | |
| %rand([rock, scissors]) => rock, rock v. paper => -1 | |
| Score12 = {fun rps:rand/2, 0}, | |
| Score12 = backTest(fun rps:rand/2, reverse(Plays6), RandFunc1, History6, []), | |
| all_tests_passed. | |
| backTest(S, Ps, RandFunc) -> %S - Strategy, Ps - OppPlays | |
| backTest(S, reverse(Ps), RandFunc, [], []). | |
| backTest(S, [], _RandFunc, _History, Pairs) -> | |
| %Process the Pairs accumulator: | |
| Score = lists:sum(lists:map( | |
| fun({R, P}) -> outcome(result(R, P) ) end, %R => Response based on opponent's History, | |
| Pairs %Acummulator here! %P => opponent's current Play | |
| )), | |
| {S, Score}; %Return Strategy with its backTest() Score. | |
| backTest(S, [P|Ps], RandFunc, History, Pairs) -> | |
| backTest(S, Ps, RandFunc, [P|History], [ {S(History, RandFunc), P} | Pairs]). | |
| %------Utility functions: | |
| get_elmt_test() -> | |
| a = get_elmt(1, [a, b, c]), | |
| b = get_elmt(2, [a, b, c]), | |
| c = get_elmt(3, [a, b, c]), | |
| all_tests_passed. | |
| get_elmt(1, [P|_]) -> | |
| P; | |
| get_elmt(N, [_P|Ps]) when N>=1 -> | |
| get_elmt(N-1, Ps). | |
| %----------------- | |
| reverse_test() -> | |
| [] = reverse([]), | |
| [2, 1] = reverse([1, 2]), | |
| [1, 2, 3] = reverse([3, 2, 1]), | |
| all_tests_passed. | |
| reverse(L) -> reverse(L, []). | |
| reverse([], Acc) -> | |
| Acc; | |
| reverse([X|Xs], Acc) -> | |
| reverse(Xs, [X|Acc]). | |
| %--------- | |
| member_test() -> | |
| false = member(3, []), | |
| false = member(3, [1, 2, 4]), | |
| false = member(-1, [-2, 0, -2, -3]), | |
| true = member(3, [3]), | |
| true = member(3, [1, 1, 3, 1, 2]), | |
| true = member(3, [2,3]), | |
| all_tests_passed. | |
| member(_, []) -> false; | |
| member(N, [N|_]) -> true; | |
| member(N, [_|Xs]) -> | |
| member(N, Xs). | |
| %----------- | |
| len_test() -> | |
| 0 = len([]), | |
| 1 = len([-1]), | |
| 2 = len([0, -1]), | |
| 3 = len([1, -1, 0]), | |
| all_tests_passed. | |
| len(L) -> | |
| len(L, 0). | |
| len([], Count) -> | |
| Count; | |
| len([_|Xs], Count) -> | |
| len(Xs, Count+1). | |
| %---------- | |
| count_test() -> | |
| 0 = count(3, []), | |
| 1 = count(-1, [1, -1, 2]), | |
| 2 = count(0, [1, 0, -1, 0, -2, -1]), | |
| 3 = count(1, [1, 0, 1, 3, 1]), | |
| 4 = count(1, [1, 1, 1, 1]), | |
| all_tests_passed. | |
| count(_, []) -> 0; | |
| count(N, L) -> | |
| count(N, L, 0). | |
| count(_, [], Count) -> | |
| Count; | |
| count(N, [N|Xs], Count) -> | |
| count(N, Xs, Count+1); | |
| count(N, [_|Xs], Count) -> | |
| count(N, Xs, Count). | |
| %--------- | |
| my_hd_test() -> | |
| a = my_hd([a, b, c]), | |
| b = my_hd([b]), | |
| all_tests_passed. | |
| my_hd([X|_]) -> X. | |
| %---------- | |
| print(Term) -> | |
| io:format("~w~n", [Term]). |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment