FileMakerでWhile関数を使ってヌジョレーボーボー

# はじめに
## 元記事（元ネタ）
[ヌジョレーボーボー
https://qiita.com/mattn/items/ae764601862b0073071e](https://qiita.com/mattn/items/ae764601862b0073071e)

## 対象読者
* 元ネタ好きな人
* FileMaker Pro / ProAdvanced ( 以下 FMPA と略す ) ユーザー
* FMPA 18 で新たに追加された While 関数の実例を見てみたい人

## 要旨
* ボ／ジョ／レ／ヌ／ボ の 5 つを用いて、長音の位置を変えず、ランダムに先の 5 つを並べ変えて出力する
    * 出力例 : ヌジョレーボーボー, ジョヌボーボーレー, レボジョーボーヌー, ...
* shuffle なんて便利な関数の存在しない FMPA でがんばる

## 参考 : While 関数について
* While 関数の基本構造は以下の通りになります。

```
While (
  [
    /* 変数設定 */
  ];

   /* ループし続ける条件 */ ;

  [
    /* ループしている間の処理ロジック */
  ];

  /* 返値 */
)
```

* While 関数についてのドキュメントは右記の通り https://fmhelp.filemaker.com/help/18/fmp/ja/index.html#page/FMP_Help/while.html




# 本題
## 出力結果
まずは出力結果をお見せします。
ランダム 10 行出力するスクリプトを用意して、それを 3 回ほどまわしてみました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/98f9c61f-03ed-53a7-ea06-fa579df10874.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/ab73569e-0fee-dcb2-7405-2e9d1609c5e5.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/384a5cf9-eed2-0d15-6130-96a5921be7f3.png)

きちんと全て別々に出力されています。

スクリプトの全体像はこんな感じです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/37739/090c3aef-49c8-ea58-ef42-4d55f7793bb4.png)

ここの $result 変数の計算式の中身が、本題ですね。

## 計算式の中身
以下のようになりました。
（分かりやすくするため 10 行表示するための $result 再代入の部分は除いています）

```
Let (
  [
    $c[1] = "ボ";
    $c[2] = "ジョ";
    $c[3] = "レ";
    $c[4] = "ヌ";
    $c[5] = "ボ";
    s = "ー";
    eval = "Int ( 5 * Random ) + 1";

    a = Evaluate ( eval );
    b = While (
          [
            a = a;
            b = a
          ];
          ( b = a );
          [ b = Evaluate ( eval ) ];
          b
        );
    c = While (
          [
            a = a;
            b = b;
            c = a
          ];
          ( c = a ) or ( c = b );
          [ c = Evaluate ( eval ) ];
          c
        );
    d = While (
          [
            a = a;
            b = b;
            c = c;
            d = a
          ];
          ( d = a ) or ( d = b ) or ( d = c );
          [ d = Evaluate ( eval ) ];
          d
        );
    e = While (
          [
            a = a;
            b = b;
            c = c;
            d = d;
            e = a
          ];
          ( e = a ) or ( e = b ) or ( e = c ) or ( e = d );
          [ e = Evaluate ( eval ) ];
          e
        );

    result = $c[a] & $c[b] & $c[c] & s & $c[d] & s & $c[e] & s
  ];

  result
)
```

## 解説
えー……見たままな感じなので、あまり解説のしどころもないような……ですが……

### 基本設計
Let 関数の変数定義でゴリゴリ計算させて、出力結果は最後の result だけで済ませています。
$c[n] の n にあたる数字は計算による代入が可能だったので、これをもって並べ替えをおこなうことにしました。

### 変数まわり
While 関数の変数スコープですが、上位から継承していて閉じられていないので、要注意です。引数の受取みたいなことができないので、仕方ない仕様なのでしょうけれども。

なるべく短くしよう、という必死の抵抗が見られるのが、ランダムに数字出力させる部分を Evaluate 関数で変数評価していたり、といったところでしょうか。

なお、変数 $c[n] における c は character の c ですが、連番の変数 c とかぶってるので、名付けとして適正なものではありません……

また、変数 s は separetor の s ですが、実際にちゃんとしたコーディングをするときは一文字変数を用いることは、イテレータとしてしばしば用いられる i 以外はオススメしません。こんな記事を見て参考にする人はいないと思いますが、念のため……

### 実行速度
実行速度は一瞬です（計測まではしていませんが体感で 300 ミリ秒以内程度）

### ループ継続条件
While のループ継続条件における ( c = a ) or ( c = b ) といったところも、本当はもっと綺麗に処理したかったのですが……
たとえば PatternCount 関数で PatternCount ( c ; a & b ) みたいな感じで判定できないかな？　と試してみたところ、何をしても（ RomanZenkaku とか GetAsText とか噛ませてみても）数値として評価されてしまうようで無理でした。


# 終わりに
全体的に、力業すぎん？　と思われること必至ですが、よりスマートな別解があればぜひコメント欄にお寄せ頂きたく！