Jump to content

Erlang Programming/Behaviors/gen server

From Wikibooks, open books for an open world

Example program for the OTP behaviour, gen_server.

Here is an example program using gen_server to create a simple text game.

  -module(rock).
  -author("Eric Evers").
  -behaviour(gen_server).
  % --------------------------------------------------------------- 
  % Example of a gen_server
  %  Purpose: a tutorial on gen_server
  %  Program: a program that plays "rock, paper, scissors" 
  %    in spanish and english 
  %  Topics covered:
  %     * starting a gen_server
  %    * stoping a gen_server 
  %    * using a gen_server to play a simple game 
  %    * make a call within a call
  %    * use calls and casts 
  %
  % For more information see:  
  %
  % References: 
  %   Author:   Ericsson AB
  %   Document: Erlang documentation
  %   Section:  OTP Design Principles 
  %   Page:     Gen_Server Behaviour  
  % ----------------------------------------------------------------
  %
  % - for internal use 
  -export([init/1, handle_call/3, handle_cast/2]). 
  -export([handle_info/2, terminate/2, code_change/3]).
  
  % - quick halt (note: casts are Asynchronous)
  -export([stop/0]).
  
  % - for external use (note: calls are Synchronous)
  -export([start/0, translate/1, juego/1, list/0, play/1]).
  
   % @start the server
  start() ->             gen_server:start_link({local, ?MODULE}, ?MODULE, [], []).
  list()  ->             gen_server:call(?MODULE, {list}).
  translate(Word) ->     gen_server:call(?MODULE, {translate, Word}).
  %
  % use juego to play the game using spanish words
  juego(Word) ->         gen_server:call(?MODULE, {juego, Word}).
  
  % use play to play the game using english words 
  play(Word) ->        gen_server:call(?MODULE, {play, Word}).
  %
  % init
  init([]) -> Dictionary = dict:from_list(
    [{rock,roca},{paper,papel},{scissors,tijeras}]),
    {ok, Dictionary}.
  %
  % handle_call
  handle_call({list}, _From, Dictionary) ->
    Response = dict:to_list(Dictionary),
    {reply, Response, Dictionary};
  %
  % Here we make a call within a call
  handle_call({play, Word}, _From, Dictionary) ->
    Status = dict:is_key(Word, Dictionary),
    if
        Status == true ->
            SWord = dict:fetch(Word, Dictionary),
            {reply, Response, _} = 
                handle_call({juego, SWord}, _From, Dictionary);
        true -> 
            Response = your_word_is_not_valid
    end,
    {reply, Response, Dictionary};
  %   
  handle_call({juego, Word}, _From, Dictionary) ->
    List = dict:to_list(Dictionary),
    {_English, Spanish} = lists:unzip(List),
    Indexes = lists:seq(1, length(Spanish)),
    Enumerated = lists:zip(Spanish, Indexes),
    Enumerated_dictionary = dict:from_list(Enumerated),
    {_H,_M,S} = time(),
    N = (S rem length(Spanish)) + 1,
    Pick = lists:nth(N, Spanish),
    io:format("you play: ~w \n",[Word]),
    P = dict:fetch(Word, Enumerated_dictionary),
    Delta = ((N+3)-P) rem 3,
    Response = case Delta of
        0 -> {'I',picked,Pick,its_a,draw};
        1 -> {'I',picked,Pick,you,loose};
        2 -> {'I',picked,Pick,you,win};
        true -> {unknown, result}
    end,
    {reply, Response, Dictionary};
  %    
  handle_call({translate, Word}, _From, Dictionary) ->
    Response = case dict:is_key(Word, Dictionary) of
        true ->
            dict:fetch(Word, Dictionary);
        false ->
            {word_not_known, Word}
    end,
    {reply, Response, Dictionary};
  %
  handle_call(_Message, _From, Dictionary) -> {reply, error, Dictionary}.
  % - 
  stop() ->
    gen_server:cast(?MODULE, stop).
  %
  terminate(normal, _State) -> 
    ok.
  %
  handle_cast(stop, State) ->
    {stop, normal, State};
  %   
  % - lets keep the compiler quiet with all the call-backs
  handle_cast(_Message, Dictionary) -> {noreply, Dictionary}.
  handle_info(_Message, Dictionary) -> {noreply, Dictionary}.
  code_change(_OldVersion, Dictionary, _Extra) -> {ok, Dictionary}.
  
  % - sample output -----------------------------
  % c(rock).
  %   <compile is done>
  % rock:start().
  %   <server started>
  %
  % 67> rock:juego(tijeras).
  % you play: tijeras
  % {'I',picked,roca,you,loose}
  %
  % 68> rock:juego(tijeras).
  % you play: tijeras 
  % {'I',picked,papel,you,win} 
  %
  % 69> rock:juego(tijeras).
  % you play: tijeras  
  % {'I',picked,tijeras,its_a,draw}
  % ----------------------------------------------------