はじめに
元記事(元ネタ)
ヌジョレーボーボー
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 回ほどまわしてみました。
きちんと全て別々に出力されています。
スクリプトの全体像はこんな感じです。
ここの $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 とか噛ませてみても)数値として評価されてしまうようで無理でした。
終わりに
全体的に、力業すぎん? と思われること必至ですが、よりスマートな別解があればぜひコメント欄にお寄せ頂きたく!