Erlang gen_fsmで作る鳴き続ける猫

有限ステートマシンを簡単に実装できるOPTのgen_fsm ビヘイビア（behaviour）を利用して、鳴き続ける猫とたまに逃げる猫を実装してみました。

![スクリーンショット 2016-06-15 12.06.41.png](https://qiita-image-store.s3.amazonaws.com/0/65312/8a5b36e1-ae08-a227-258b-d818c8179a78.png)
![スクリーンショット 2016-06-15 12.06.44.png](https://qiita-image-store.s3.amazonaws.com/0/65312/3fa31ed9-89b7-17fe-b55e-9725fc3d78f9.png)


# 1. 鳴き続ける猫

```erlang:neko.erl
-module(neko).
-author("hami").
-behaviour(gen_fsm).

%% API
-export([start_link/1, cat/2, action/0]).
-export([init/1]).

start_link(CatName) ->
  gen_fsm:start_link({local, neko}, neko, CatName, []).

init(CatName) ->
  {ok, cat, CatName}.

action() ->
  gen_fsm:send_event(neko, []).

%% 猫本体
cat(FromAction, CatName) ->
  %% 鳴く
  print(string:concat(atom_to_list(CatName), ":< meow")),

  %% 次の状態
  {next_state, cat, CatName}.


%% printer
  print(Message) -> io:format("E: ~p~n",[Message]).

```

```erlang:main.erl
-module(main).
-author("hami").

%% API
-export([main/0]).

main() ->
  %% 猫生成
  neko:start_link(shiro),

  %% アクションを実行
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action().

```

```shell-session:make.sh
# コンパイルと実行
echo "+++++++++++++"
erlc ./neko.erl
erlc ./main.erl
echo "+++++++++++++"
erl -noshell -s main main -s init stop
echo "+++++++++++++"

```

```shell-session:実行結果
+++++++++++++
E: "shiro:< meow"
E: "shiro:< meow"
E: "shiro:< meow"
E: "shiro:< meow"
E: "shiro:< meow"
E: "shiro:< meow"
+++++++++++++
```


# 2. たまに逃げる猫
![スクリーンショット 2016-06-15 12.06.44.png](https://qiita-image-store.s3.amazonaws.com/0/65312/8d2b2260-d0e6-23d8-7817-336e043f856a.png)


```erlang:neko.erl
-module(neko).
-author("hami").
-behaviour(gen_fsm).

%% API
-export([start_link/1, cat/2, action/0]).
-export([init/1]).

start_link(CatName) ->
  gen_fsm:start_link({local, neko}, neko, CatName, []).

init(CatName) ->
  {ok, cat, {CatName, sleep, 0}}.

action() ->
  gen_fsm:send_event(neko, []).

%% 猫本体
cat(FromAction, {CatName, CatStatus, StrokeCount}) ->
  case CatStatus of
    sleep ->
      %% 鳴く
      print(string:concat(atom_to_list(CatName), ":< meow")),

      %% 次の状態
      if StrokeCount + 1 < 3 ->
        {next_state, cat, {CatName, sleep, StrokeCount + 1}};
      StrokeCount + 1 >= 3 ->
          {next_state, cat, {CatName, standing, 0}}
      end;

    standing ->
      %% 逃げる
      print(string:concat(atom_to_list(CatName), " ran away...")),

      %% 次の状態
      if StrokeCount + 1 < 3 ->
        {next_state, cat, {CatName, standing, StrokeCount + 1}};
        StrokeCount + 1 >= 3 ->
          {next_state, cat, {CatName, sleep, 0}}
      end;

    _ ->
      null
  end.


%% printer
  print(Message) -> io:format("E: ~p~n",[Message]).

```

```erlang:main.erl
-module(main).
-author("hami").

%% API
-export([main/0]).

main() ->
  %% 猫生成
  neko:start_link(kuro),

  %% アクションを実行
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action(),
  neko:action().


```

```shell-session:make.sh
# コンパイルと実行
echo "+++++++++++++"
erlc ./neko.erl
erlc ./main.erl
echo "+++++++++++++"
erl -noshell -s main main -s init stop
echo "+++++++++++++"

```

```shell-session:実行結果
+++++++++++++
E: "kuro:< meow"
E: "kuro:< meow"
E: "kuro:< meow"
E: "kuro ran away..."
E: "kuro ran away..."
E: "kuro ran away..."
E: "kuro:< meow"
E: "kuro:< meow"
E: "kuro:< meow"
E: "kuro ran away..."
E: "kuro ran away..."
E: "kuro ran away..."
E: "kuro:< meow"
+++++++++++++
```