Archive

Posts Tagged ‘lists’

A card game in erlang…continue!

December 9, 2009 2 comments

Here I am with a new post!

A couple of days ago, I had some time to fix my erlang environment in my new Ubuntu Karmic Koala, so I decided to continue with the development of my cards game in erlang.

If you remember from my previous posts, I did a process for handling the table, it was a gen_server providing a basic interface for a set of actions users may want to perform, as “play a card on the table”, “take a single card/a set of cards from table”, “give me 10 cards” and so on…

This process was also responsible for checking whether the action user wants to do is allowed (e.g. is the card user wants to take in the table), so I thought that next step would have been the creation of another gen_server.

In my mind this server should have listened to a specific port waiting for users; since “scopa” is a game played by 4 users, the server should have waited until 4 users joined the game, than it would have started a new table process for these users.

Now I’m going to write some code, and discuss it with you.

Let’s start with some handle_calls for our gen_server:

handle_call({add, Socket}, _From, State) ->
    NewSockets = [Socket | State#state.sockets],
    Reply = ok,
    NewState = #state{sockets=NewSockets},
    {reply, Reply, NewState};

The previous handle_call adds a new socket to the list of sockets stored in the state of the gen_server; I use the sockets to distinguish each player.

handle_call(get_players_number, _From, State) ->
    PlayersNum = length(State#state.sockets),
    Reply = PlayersNum,
    {reply, Reply, State};

The previous handle_call is used to retrieve the number of users who joined already the game.

handle_call(get_players_sockets, _From, State) ->
    PlayersSockets = State#state.sockets,
    Reply = PlayersSockets,
    {reply, Reply, State};

The previous handle_call is used to retrieve the list of sockets in the game (we can use this to understand whether the socket sending commands is a valid user)

handle_call(get_player_turn, _From, State) ->
    [PlayerSocket | _Others] = State#state.sockets,
    Reply = PlayerSocket,
    {reply, Reply, State};

The previous handle_call is used to retrieve wich user/socket is the next to perform an action (so we can manage turns)

handle_call(update_turn, _From, State) ->
    [PlayerSocket | Others] = State#state.sockets,
    NewSockets = Others ++ [PlayerSocket],
    NewState = #state{sockets=NewSockets},
    Reply = ok,
    {reply, Reply, NewState}

The last handle_call is used to update the turn list after a player submit an action.

Let’s say that a player sends a command to our server…before forwarding this command to the table we must check whether the user who sent the command is a player of the match and whether he is the player we expect to play (turn); we may want to use two functions like:

%%--------------------------------------------------------------------
%% Func: is_player(Socket) -> true | false
%% Description: Given a socket checks whether it represents a user in
%%              current match
%%--------------------------------------------------------------------
is_player(Socket) ->
    lists:member(Socket, gen_server:call(?MODULE, get_players_sockets)).

and

%%--------------------------------------------------------------------
%% Func: is_player_turn(Socket) -> true | false
%% Description: Given a socket checks whether the user it represents
%%              is the one expected to play
%%--------------------------------------------------------------------
is_player_turn(Socket) ->
    Socket == gen_server:call(?MODULE, get_player_turn).

Next time new stuff! Stay tuned!

Categories: English, Erlang Tags: , , , ,

Shuffle a list (deck)

October 27, 2009 Leave a comment

Dopo che avete creato un mazzo di carte per un qualsiasi gioco voi stiate implementando, si pone il problema di mescolare tale mazzo, in modo da ottenere una versione dello stesso in cui le carte non siano piu ordinate per valore e seme, ma seguano un ordine casuale.

Dopo essermi sbattuto un po su google, ho trovato un paio di risorse: un algoritmo da seguire in questi casi, il FISHER-YATES (Knuth shuffle) e un po di codice gia implementato dai simpatici ragazzi di TRAP-EXIT e LITERATEPROGRAMS.

Dopo aver letto entrambi gli articoli sono arrivato al seguente codice, ottenuto dal codice di TRAP-EXIT modificando alcuni nomi di variabile:

shuffle(Deck) ->
   randomize(round(math:log(length(Deck)) + 0.5), Deck).

randomize(1, Deck) ->
   randomize(Deck);

randomize(T, Deck) ->
   lists:foldl(fun(_E, Acc) ->
                  randomize(Acc)
               end, randomize(Deck), lists:seq(1, (T - 1))).

randomize(Deck) ->
   D = lists:map(fun(A) ->
                    {random:uniform(), A}
             end, Deck),
   {_, D1} = lists:unzip(lists:keysort(1, D)),
   D1.

La complessita asintotica di tale codice viene quantificata come O(n log n).

A seguire il codice di LITERATE PROGRAMS, come potete vedere questa implementazione appare molto piu compatta…

shuffle(Deck) -> shuffle(Deck, []).

shuffle([], Acc) -> Acc;

shuffle(Deck, Acc) ->
  {Leading, [H | T]} = lists:split(random:uniform(length(Deck)) - 1, Deck),
  shuffle(Leading ++ T, [H | Acc]).

In questo caso il risultato della complessita asintotica appare essere O(n)….
Ora sta a voi decidere quale implementazione usare…o se farvene una vostra…e ricordate di passare nei siti da cui ho tratto i codici listati sopra!

 

Categories: Erlang Tags: , , ,

Configuration file in Erlang

September 26, 2009 1 comment

Quando scrivete un progetto in erlang, grande o piccolo che sia, vi troverete davanti alla necessità di spostare con il codice hard-coded in un foglio di configurazione, che l’utente avrà la possibilità di modificare a piacere.

In erlang tutto ciò è molto semplice, tanto da poter essere implementato in poche righe di codice.

Iniziamo creando un file di configurazione che metteremo nella directory di Unix /etc/software/software.cfg

Possiamo creare tale file usando il comando vim dalla shell di Unix, oppure un qualsiasi editor di testo (nota bene che la cartella /etc/ è di solito di proprietà dell’utente root, quindi o eseguite tali comandi come tale utente, o cambiate directory con una vostra directory locale.

pegaso:~ bellerofonte$ sudo mkdir /etc/software
pegaso:~ bellerofonte$ sudo vim /etc/software/software.conf

E qui editate il file aggiungendo i parametri che vi pare (i miei rappresentano il mio blog), seguendo però la seguente forma:

{nome, "Paolo D'Incau's Blog"}.
{url, "http://pdincau.wordpress.com/"}.
{framework, "WordPress"}.

Ogni campo viene identificato con una tupla a due campi: il primo è un atom che identifica la tupla (tag), mentre il secondo è il valore associato a tale tag e può essere un qualsiasi tipo erlang (lista, tupla, atom etc etc).

E’ importante che mettiate il punto alla fine di ogni riga e che controlliate che ogni tupla sia corretta nella sintassi.

Ora come carichiamo tali tali nel nostro codice erlang?

Ecco la risposta:

>1 {ok, Conf} = file:consult("/etc/software/software.cfg").
{ok,[{nome,"Paolo D'Incau's Blog"},
     {url,"http://pdincau.wordpress.com/"},
     {framework,"WordPress"}]}

Come vedete il risultato della funzione consult/1 del modulo file è una tupla. Nel caso tutto sia giusto, tale tupla sarà composta dall’atom ok e dalla lista dei valori nel file di configurazione.

Io metto {ok, Conf} confidente nel fatto che facciate tutto giusto, ma se cosi non fosse otterreste questo errore:

>1 {ok, Conf} = file:consult("/etc/software/software.cfg").
** exception error: no match of right hand side value {error,enoent}

Ok, ora come recuperiamo tra questi valori un singolo valore che ci interessa?
Ecco una possibile soluzione:

4> lists:keysearch(nome, 1, Conf).
{value,{nome,"Paolo D'Incau's Blog"}}

In questo caso ho utilizzato la funzione keysearch/3 del modulo lists. Essa prende in ingresso, una tag, un intero (che rappresenta quale posizione della tupla deve avere tale tag) e una lista di tuple.

Categories: Erlang Tags: , , , ,
Follow

Get every new post delivered to your Inbox.

Join 25 other followers