見出し画像

【Adalo】重複しない乱数を作ってみた

(なぜこれを書いたか)
最近はClickでNoCodeアプリを作っていますが、ある時、重複しない乱数を作ってみようと思い、考え始めたのですが、どうしても出来ませんでした。ならばAdaloでやってみようと思い、簡易的なものをとりあえず作ったので備忘録を兼ねてまとめておくことにしました。(Adaloではカウントダウンタイマーを使ってやったのですが、Clickには同様の機能が無く、一度にデータベースの各行の値を更新するという事が出来ませんでした。)

そもそも「重複しない乱数」を作ろうとしたきっかけは、ランダムに出題されるクイズアプリを作ろうとしたからです。乱数はランダム関数RAND()で簡単に作ることが出来ますが、これを使うとどうしてもダブリが出てくるのでこれを無くしたアプリを作りたかったのです。(RAND関数を使うと2,3,3,7,4,4,9・・・というように重複する可能性があるという事です)

クイズ以外でもいろいろな使い方があります。例えば、仲間10人のうち3人が商品(1等賞、2等賞、3等賞)をもらえるアプリがあったとすると、同じ人が2回も3回も選ばれてはいけません。ダブリなく、一人1回限りという条件を満たして欲しいわけです。

しかし、重複しない乱数は結構難解です。ネットで調べるといろいろ出てきます。歴代の数学者があれこれ考えて、確立されたやり方がいくつもあります。中でも「フィッシャーとイェーツのシャッフル(乱数理論)」というのが一番しっくりきましたが、この難解なアルゴリズムをNoCodeで実現することは出来ません。Javascriptの作成例などが載っていましたが、もっと簡単に作る方法は無いものかずっと考えてきました。

今回紹介するのはNoCodeで作れる「なんちゃって乱数」です。私自身もうちょっとスマートに出来ないものかと今でも思っています。もしこれを読んでこうした方がいいよというアドバイスをくれる人がいたら是非お願いします。

1.重複しない乱数のロジック

~アプリの内容~
今回作ろうとしているのはクイズアプリです。全部で5問あり、1から5の番号が振られています。出題は1問づつ、ランダムに表示されます。5問終了すると「クイズをリセットして下さい」という表示が出て、ボタンを押すとまた別の順序で問題が出てくるようになっています。(問題の内容は変わりません。出題の順番が変わるだけです)

(参考アプリ) 動きます(Login等無し)

https://previewer.adalo.com/99339e73-0290-45e2-bea0-a8cd39be9c8c

~重複させないロジック~
NoCodeアプリなので簡易的なロジックでダブらない乱数を作ることにしました。クイズの問題が5問あるので以下のようなデータベースを作りました。

データベースは5行あり、各行(レコード)にはクイズ問題の他に「No」、「乱数」、「count」というプロパティを作りました。
ロジックの内容は「乱数」にカウントダウンタイマーでRAND()関数で一気に乱数を挿入し、乱数を昇順にソートしてランダムな順番を作ろうとしています。

1番上のクイズ問題が終了したら「次の問題」というボタンを押します。するとボタンに設定したActionによって一番上にあった問題が一番下に移動します。それまで上から2番目にあった問題が一番上に繰り上がります。

クイズの5問全部が終了したら「クイズをリセットして下さい」という表示が出て「クイズをリセット」というボタンを押すと、異なる順番でクイズ問題が出題されます。

(アプリの外観)
開発画面のHome画面は下記のようなイメージです。5問あるクイズ問題が乱数の順番で昇順ソートが設定されており、一番上は乱数の一番小さいものが来ています。(降順ソートでも構いませんが)

1問ずつ表示したいので2問目以降は表示しないように当初はカスタムフィルターを使って非表示にしていました。しかし5問全部終了した時にはカスタムリストから表示が無くなってしまい、カウントダウンタイマーで元に戻せなくなってしまったのでRectangleで2問目以降を隠すようにしました。(非常にみっともないので、もっとスマートなやり方が出来ないのか今も考えています)

(プレビュー画面)

2.設定の中身

①カスタムリスト
クイズデータベースと紐づけられたカスタムリストは乱数を小さい順から並べるソートの設定だけしてあります。(カスタムフィルターの設定はありません)

②カウントダウンタイマー
Home画面が開くとカウントダウンタイマーに設定された以下のActionが起こります。(クイズDBをUpdateします。タイマーは0秒で設定しています)
・乱数・・・・RAND(1,1000)で乱数を発生させ、値を「乱数」に入力します
・count・・・0を入力します。

③「次の問題」ボタンにActionを設定
クイズを1問終えたら「次の問題」ボタンを押して次に移ります。ボタンを押すと下記のActionが起こります。

・「乱数」・・・「一番大きい乱数」+1
(意味)
→クイズ問題は乱数によって昇順ソートされています。一番上のクイズ問題が終了したら、今度はクイズデータの一番下に持って行きます。そのためには乱数の一番大きな数字を取得して、それに1加えた数字を一番上の乱数の項目に入れてやります。そうすると昇順にソートされて一番下に来ます。(これを繰り返し続けることで2番目のデータ、3番目のデータが1番上に表示されるようになります。)

・「count」・・・・count+1
(意味)
そのクイズが何回選択されたかをカウントします。5問あるクイズを全部終了するとどのクイズ問題もカウントが1になっています。これをsumで合計して5になったら「クイズが一巡したのでもう一度やる場合は「クイズをリセット」ボタンを押して下さい」という表示を出します。

④「クイズをリセットする」ボタンのAction
「クイズをリセットする」ボタンを押すとHome画面の隣にある「reset」画面に移動し、また自動でHome画面に戻ってくる動きをします。
何をしているかというとHome画面が再表示されるのでカウントダウンタイマーが作動し、別の乱数が発生し、countも0に戻るという動きになります。

「クイズをリセットする」ボタンを押すと中身が何もない「reset」画面に移動しまたHomeに戻ります。

~「reset」画面のScreenAction~
Homeからreset画面に遷移したら、また自動でHomeに戻るようにするためにScreenActionを設定しておきます。「reset」画面を選択し、黄色い枠で囲まれた状態でHomeに戻るAction(Link)を設定しておきます。

⑤カスタムリストの2行目以降を隠すRectangle(四角形)

カスタムリストのデータは乱数の値で昇順ソートされており、クイズは1問ずつ表示したいので2問目以降は非表示にしておきます。このためRectangle(四角形)でリストの2行目以降を隠してしまいます。(カスタムフィルターで非表示にするとクイズが全部終了したときにリスト表示が無くなってしまい、カウントダウンタイマーで初期状態に戻せなくなってしまうのでやむなくこうしています)

以上で設定に関する説明は終わりです。
このアプリの内容は、各クイズ問題ごとに乱数を発生させ、その数字でソートをかけ、1~5の順番を作ったら1問ずつ表示するというものです。
Clickでこのアプリを作れないのはカウントダウンタイマー機能が無いため各クイズ問題に一度に乱数を挿入できないからです。

文中でも書きましたがソートしたデータの一番上のデータだけ表示する方法がどうしても分かりませんでした。そのためにRectangleで隠しているのですが何とかしたいです。

カスタムフィルターを使ったり、ソートしたデータを1行だけ表示するという設定をすれば、一見出来そうな気がするんですが、そうするとクイズの2巡目の初期設定が出来なくなるのです。(カウントダウンタイマーは表示されていないと動かないという性質があるからです)

(応用例)
このアプリは英単語の暗記アプリとしても使えるかも知れません。200語くらい覚える単語があって、順番が固定だと1~20位は覚えても170~200語目位は全然覚えられないかも知れません。均等に乱数が発生するというのはいろいろ使い道があると思います。

(過去の投稿)


この記事が気に入ったらサポートをしてみませんか?