Skip to content

Instantly share code, notes, and snippets.

@niahoo
Created September 3, 2015 08:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save niahoo/2b5e12b82e3ab184b437 to your computer and use it in GitHub Desktop.
Save niahoo/2b5e12b82e3ab184b437 to your computer and use it in GitHub Desktop.
-module(random_server).
-include("../include/debugtools.hrl").
-ifdef(TEST).
-include_lib("eunit/include/eunit.hrl").
-endif.
-export([start_link/0]).
-export([uniform/0,string/2,list/2,uniform/1]).
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2, code_change/3]).
%% Public API
start_link() ->
gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
uniform() ->
gen_server:call(?MODULE, uniform).
uniform(Top) ->
gen_server:call(?MODULE, {uniform, Top}).
uniform_multi(Top,Amount) ->
gen_server:call(?MODULE, {uniform_multi, Top, Amount}).
string(ResultLength, Chars) ->
%% Le même caractère peut sortir plusieurs fois
PoolLength = length(Chars),
Randoms = uniform_multi(PoolLength,ResultLength),
string(Randoms,Chars,[]).
string([R|Randoms],Chars,Acc) ->
string(Randoms,Chars,[lists:nth(R,Chars)|Acc]);
string([],_,Acc) -> Acc.
%% récupère Amount items dans la liste aléatoirement
list(Amount, List) ->
%% Un item ne peut être tiré qu'une fois, on va donc shuffle la
%% list puis en récupérer les Amount premiers éléments
L = length(List),
%% @todo https://erlangcentral.org/wiki/index.php/RandomShuffle
ShuffleIndexes = ?MODULE:string(L, lists:seq(1,L)),
%% On attache chaque index à un élément de notre liste
ShuffleZip = lists:zip(ShuffleIndexes, List),
SortedZip = lists:sort(ShuffleZip),
%% Avec sublist() on récupère une site de la taille voulue, les N premiers
[Elem || {_I, Elem} <- lists:sublist(SortedZip, Amount)].
%% Server implementation, a.k.a.: callbacks
init([]) ->
random:seed(erlang:unique_integer()),
?inf("Random server started",[]),
{ok, nostate}.
handle_call(uniform, _From, State) ->
{reply, random:uniform(), State};
handle_call({uniform, Max}, _From, State) ->
{reply, random:uniform(Max), State};
handle_call({uniform_multi, Max, Amount}, _From, State) ->
Rep = [random:uniform(Max) || _ <- lists:seq(1,Amount)],
{reply, Rep, State};
handle_call(stop, _From, State) ->
{stop, normal, stopped, State};
handle_call(_Request, _From, State) ->
{reply, ok, State}.
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info(_Info, State) ->
{noreply, State}.
terminate(_Reason, _State) ->
ok.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
%% -----------------------------------------------------------------
-ifdef(TEST).
t1_test_() ->
{ setup
, fun() -> application:start(popos) end
, fun(_) -> application:stop(popos) end
, [ fun() ->
X = string(5,"x"),
?assertEqual(5,length(X)), %% au passage ça valide aussi que X soit une liste
?assertEqual(X,"xxxxx"),
TestLen = 100,
Y = string(TestLen,"abcd"),
CountAll = fun ($a,{As,Bs,Cs,Ds}) -> {As+1,Bs,Cs,Ds}
; ($b,{As,Bs,Cs,Ds}) -> {As,Bs+1,Cs,Ds}
; ($c,{As,Bs,Cs,Ds}) -> {As,Bs,Cs+1,Ds}
; ($d,{As,Bs,Cs,Ds}) -> {As,Bs,Cs,Ds+1}
end,
{As,Bs,Cs,Ds} = lists:foldl(CountAll,{0,0,0,0},Y),
?assertEqual(TestLen,As+Bs+Cs+Ds)
end
]
}.
-endif.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment