コミュニティアイコン プチコン 非公式コミュニティ トピック

アバター
経済さん ◆LjHuF5fUoor/
2020/8/13 10:30
質問
重複のない乱数値を生成する方法
0から9までの乱数値を4つ作るときに、それを被らせないようにする方法はありますか? あったらでいいのでどなたか教えて下さると、とても有難いです。

コメント

アバター
ツララ 2020/8/13 11:21 ◆ArUdBYOYME1V
例えば0~9の10枚のカードがあって、そこからランダムに4枚引くのをイメージしてみればいいんじゃないでしょうか。
具体的には
A[10]っていう配列を作って、0から9までの数値を格納しておいて
LEN()命令を引数にしたRND()命令で、配列の個数を最大値としたランダムな数字を抽選して取り出しつつ
COPY命令とPOP()命令で取り出す配列Aの長さを削っていくとか。

DIM A[10],ANS[4],P,Q,I,D
COPY A,"@LIST",10
@LIST DATA 0,1,2,3,4,5,6,7,8,9
FOR I=0 TO 3
 P=LEN(A)
 Q=RND(P)+1
 ANS[I]=A[Q-1]
 COPY A,Q-1,A,Q,P-Q
 D=POP(A)
NEXT
アバター
あんちもん 2020/8/13 11:23 ◆8qCJSJ1bKTIQ
昔作ったゲームで0から9の値を重複しないようランダムに配列に格納する処理があったので引っ張り出してきました。参考になれば幸いです。
Fisher-Yatesのアルゴリズムというらしいです。
乱数値が4つだけ必要ならこのARY[0]〜ARY[9]の値のうち4つを適当に使って下さい。

追記
画像のコードだとARY[9]に9が入らなくなっちゃったりしますね。
SWAP ARY[A],ARY[RND(A+1)]
に直して下さい。
アバター
Na 2020/8/13 14:35 ◆QoELVrBXBQCI
シンプルに、被ったらもう一度乱数をやり直す。
効率的ではないですが分かりやすいと思います。

DIM A[4]
FOR I=0 TO 3
 @RND
 A[I]=RND(10)
 FOR J=0 TO I-1
  IF A[I]==A[J] THEN @RND '今までに出てたらやり直し
 NEXT
NEXT

GOTOの代わりにREPEATで囲うとかI=I-1するとかでもいいです。
答えを配列に入れずに文字列にしてINSTRで探したらちょっと速いかもしれませんが、4つぐらいなら特に速さや効率は気にしなくていいかなと思います。
アバター
あまさとしおん 2020/8/13 14:46 ◆mzDKTVUAtwqE
まだSORTは出てきてない?
0-9の数字が入ったA配列と、RND()の数字が入ったB配列を用意して
SORT B,A
こうじゃ

あとはPOPか何かで1個ずつ必要な分だけ出せばいいのじゃ
アバター
ツララ 2020/8/13 19:58 ◆ArUdBYOYME1V
経済さんがまず最初に思った方法を聞いてみたい。
多分それをどう実装するかが思い付かなかったからこのトピック立てたんでしょうし。

あんちもんさんの方法は、最初に手持ちのカードをシャッフルしてランダムな山札にしてから順番に取り出す方式。
Naさんの方法は、取り出したカードをまた場に戻して目隠し状態で無造作に取り出して、メモと照合して条件に合致した場合だけ採用する方式。
あまさとさんの方法は、ほぼあんちもんさんのと同じだけどシャッフルの方法が違う方式。
それぞれメリット・デメリットあるでしょうけど
「被らない」っていうポイントについて言えば
ランダム抽選を予めやっておくか、ランダムな結果に更に判定処理を加えるか、ランダムな結果を受けて抽選範囲を操作するか
で実装してるわけですな。
多分まだ別の方法はあるでしょうけど。
アバター
こういち 2020/8/13 22:51 ◆.Id/aHiU36hu
いろいろ方法が出たけど、個人的なおすすめは最速のFisher-Yatesのアルゴリズムかな。しおんさんのSORTも簡潔であり。

速度的にはあんちもんさんの書いたFisher-Yatesのアルゴリズムと、さすらいの名無しさんのそれが最速で、しおんさんのSORT,Naさんのそれ,ツララさんのそれの順で速い。まぁ10種類なのでそこまで速度差は出ませんが。

しおんさんのSORT、配列Bに入れるのはRND()じゃなくてRNDF()の方が安心で簡潔。
アバター
経済さん 2020/8/13 22:59 ◆LjHuF5fUoor/
ツララさん、あんちもんさん、さすらいの名無しさん、Naさん、あまさとしおんさん、こういちさん、分かりやすいご説明有難うございます。m(_ _)m
アバター
経済さん 2020/8/13 23:13 ◆LjHuF5fUoor/
>ツララさん
 最初に思った方法というか最初にやって挫折した方法なのですが、
A1=RND(10)
A2=RND(10)
A3=RND(10)
A4=RND(10)
IF A1==A2 THEN A2=A2-1
IF A2==A3 THEN A3=A3-1 ...
 という感じで、もしA1とA2が被っていたらA2の値を-1するという方法を考えていました。
アバター
経済さん 2020/8/13 23:30 ◆LjHuF5fUoor/
私は今回初めてPOP、SWAP、SORTという命令があることを知りました。
皆様が挙げてくださったプログラムをそれぞれプチコン.NETを見ながら自分なりに解釈した結果、プチコンやプログラムについてまだまだ知らないことがたくさんある自分にとっては、シンプルなNaさんのプログラムが一番分かりやすく感じました。でも、他の方が挙げてくださった方法も意味を理解して使いこなせるようにしていきたいです。
アバター
ツララ 2020/8/18 13:48 ◆ArUdBYOYME1V
経済さんが最初に思った方法は、名付けるなら「椅子取りゲーム」方式ですな。
みんなでせーの!でカードを引いて、被ったら番号が後の人が前の人に譲るって言う…
でもこれ数直線作って考えて見れば分かると思うんですけど
マイナス方向だけの移動だと0で被った場合はどん詰まりですよね
被った場合の式は A2=(A2-1+10)MOD 10
・・・もっと簡単に言えば、一つズラすだけならプラス方向にズラして10で余剰を取れば…
どっちにしろ被ると必ず隣同士の数値が出てくるので面白味に欠けるし
かと言って、ズラす値をランダムにすると判別済み変数とまた被ってしまう場合も出てくるしで
新たな問題発生というところですか。
いっそのこと、被りが発生したら全部チャラにしちゃって
また4つとも抽選し直しの方が潔いかも。
被り発生を確認するにしてもIF文を並列に羅列だと冗長なので
4つの値を比較する6通りの判別式を別途計算して
@THUSEN
A1=RND(10):A2=RND(10):A3=RND(10):A4=RND(10)
D=(A1==A2)+(A1==A3)+(A1==A4)+(A2==A3)+(A2==A4)+(A3==A4)
IF D THEN @THUSEN
みたくするとか。

>こういちさん
つまんねーやつだなぁ(チコちゃん風)
(でも最初に付いたコメントが最遅だったのはボケとしては評価して欲しかったり)
アバター
キルル2 2020/8/22 9:23 ◆rGE712Ruejv7
プチコン上ではSORTの方が若干速いと思います
New3DSで10000通りから1000個の抽選を100回やったところ
SORTは約5500ms
fisherは約6000ms
かかりました

コメントを書く

  • こちらは「プチコン3号」「プチコンBIG」など、プチコンシリーズに関する話題を扱ったコミュニティです
  • プチコンシリーズにまったく関係ない書き込みはご遠慮下さい。削除の対象となります
  • こちらにはその他のゲームや雑談のコミュニティはなく、作る予定もありません (ひとりで管理できないため)。ごめんなさい
  • ユーザー登録なしで書き込みができます
  • 秘密の合い言葉は成りすましの防止 (トリップ機能)、書き込みの編集時の本人認証に使用します
  • 秘密の合い言葉に他人に推測されやすい言葉、他サービスと同じパスワードは入力しないでください。
  • 書き込むと、投稿時に入力したお名前と秘密の暗号が記憶され、ログイン状態になります

- WEB PATIO -