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


はじめに

元記事(元ネタ)

ヌジョレーボーボー
https://qiita.com/mattn/items/ae764601862b0073071e

対象読者

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

要旨

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

参考 : While 関数について

  • While 関数の基本構造は以下の通りになります。
While (
  [
    /* 変数設定 */
  ];

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

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

  /* 返値 */
)

本題

出力結果

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



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

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

ここの $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 とか噛ませてみても)数値として評価されてしまうようで無理でした。

終わりに

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