• ベストアンサー

重複しない乱数発生

初めて投稿させて頂きます。 サイコロを振って、一度出た目はもう出ないような ゲームをプログラミングしています。 Dim i As Integer Dim j As Integer Dim t As Integer Dim r(6) As Integer 'コンピュータ Dim b As Integer 'プレイヤー Private Sub Command1_Click() b = Val(Text2.Text) Randomize r(6) = Int(Rnd * 6 + 1) '1~6までの乱数発生 Text1.Text = r(6) For i = 1 To n r(i) = i 'r(i)~r(n)に1~nの値を格納 Next i For i = n To 2 Step -1 j = Int((i - 1) * Rnd() + 1) '1~i-1の範囲の乱数 t = r(i): r(i) = r(j): r(j) = t 'r(i)とr(j)の交換 Next i For i = 1 To n Text1.Text = r(i) Next i If r(i) < j Then Label2.Caption = "あなたの勝ちです" Else Label2.Caption = "あなたの負けです" End If 幾つか考えてこれで落ち着いたのですが、これでは まだ重複してしまいます。 どこが問題なのかご指摘頂けるようお願いします。 一度出た目は出ないようにするので、全部で6回試行 することになります。またその6回分の結果を表示したいのですが、 Text3.Text = r(1) Text4.Text = r(2) Text5.Text = r(3) Text6.Text = r(4) Text7.Text = r(5) Text8.Text = r(6) としてしまうと全てに0が表示され、結果が表示されません。 これについても回答をお願いします。 まだ初心者ですが、よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
回答No.10

#6,8,9です。 さっきのは、全ての乱数が出るまで探し続けるほうほうでしたが、違う方法もあります。 さっきの方法ですと、乱数の範囲が広いと最後の1個が出る確率が減り、処理時間が多くなります。数百程度の組み合わせなら気になりませんが・・・ 下は、違う方法の参考例です。 先にformloadで、解を配列に格納します。何もしないうちは、配列の格納番号がそのまま解になります。 そして、乱数で出た配列は0にします。 乱数を出した後で、0を探して、見つかればそれ以降の配列データを1個づつずらします。 次に乱数の範囲を1つ減らしていきます。 この方法ですと、探したい回数分しか乱数は実行されません。 まぁ乱数の幅がどの程度になったときに、速さが逆転するのか、あるいは逆転しないかは検証した事がないので判りませんが・・・ Private ANS(10) As Integer Private RndWhdth As Integer Private Sub Form_Load() Dim i As Integer RndWhdth = 10 For i = 1 To 10 ANS(i) = i Next End Sub Private Sub Command1_Click() Dim A As Integer Dim i1 As Integer Dim i2 As Integer Dim DmyANS As Integer If RndWhdth = 0 Then MsgBox ("END") RndWhdth = 10 For i = 1 To 10 ANS(i) = i Next Exit Sub End If A = Int(Rnd * RndWhdth) + 1 Text1.Text = ANS(A) ANS(A) = 0 For i1 = 1 To RndWhdth If ANS(i1) = 0 Then For i2 = i1 To RndWhdth - 1 ANS(i2) = ANS(i2 + 1) Next RndWhdth = RndWhdth - 1 Exit Sub End If Next RndWhdth = RndWhdth - 1 End Sub

kuru0338
質問者

お礼

わざわざプログラムを組んで頂き、大変感謝しております。 すごくわかりやすかったので、重複しない乱数を発生することが出来ました。ありがとうございます。 あと結果を表示したいのですが、色々やってみているのですがなかなか出来ません。 ボタンをクリックするごとに、所定のテキストに結果を表示していきたいのですが、このプログラムだとANS(A) = 0となっているので結果表示の際ANS(A)は使えないのでしょうか?

その他の回答 (9)

回答No.9

#6,8です。 あまり綺麗に書いてなかったので、ちょっと書き直しました。 5列×50行です。全部出るまで探します。 それとクリアボタンを追加してあります。 Private BINGO(5, 50) As Integer Private Counter As Integer Private Sub Command1_Click() Dim A As Integer Dim B As Integer Dim C As String Dim i As Integer BINGO(0, 0) = 1 Counter = Counter + 1 If Counter > 250 Then MsgBox ("END") Exit Sub End If Do While BINGO(A, B) = 1 A = Int(Rnd * 5) + 1 B = Int(Rnd * 50) + 1 Loop Select Case A Case 1 C = "B-" Case 2 C = "I-" Case 3 C = "N-" Case 4 C = "G-" Case 5 C = "O-" End Select Text1.Text = C & B BINGO(A, B) = 1 End Sub Private Sub Command2_Click() Dim A As Integer Dim B As Integer Counter = 0 For A = 1 To 5 For B = 1 To 50 BINGO(A, B) = 0 Next Next End Sub

kuru0338
質問者

お礼

結果を表示するのは、リストボックスを用いることでなんとか自分で解決できました。 本当にわざわざプログラム組んで頂きありがとうございます! とてもためになりました!

回答No.8

>BINGO(5, 10)なので、5行10列のビンゴカードですよね? そうです。ですので、例えば5行×50列にしたければ、 Private BINGO(5, 50) As Integer If i > 5000 Then と、します。5000と言う数字が良いかどうかは判りません。 >BINGO(0, 0) = 1とBINGO(A, B) = 1は初期値に戻しているのでしょうか これの考え方を先に説明します。 BINGO(XX,YY)の配列はフラグとして使用します。 配列はXX,YYの部分がアドレスに相当します。ですので、乱数で得られたXXとYYの組み合わせが過去に出たか出なかったかを、1と0で見分けます。 次に BINGO(0, 0) = 1 と、している部分ですが、プログラム起動時には配列を含む全ての変数には0が入っていますので、 Do While BINGO(A, B) = 1 と、している部分でAとBは乱数を出す前ですので夫々0になっています。 つまり、 Do While BINGO(0, 0) = 1 となるわけです。 Do While は、While 後の条件式を満たしていなければLoop以降の部分に抜けてしまいますので、先に BINGO(0, 0) = 1 として、BINGO(0, 0) = 0の初期値をBINGO(0, 0) = 1にします。 これで、乱数部分のプログラムが実行されます。 後は、乱数で出たBINGO(A,B)が1(過去に出ていれば)ならばLOOPして、乱数を取り直します。 逆に、乱数で出たBINGO(A,B)が0(初めて出たのならば)ならばLOOPを抜けて表示して、BINGO(A,B)を1にします。 あと、 If i > 50 Then MsgBox ("END") Exit Sub End If の部分ですが、ここは無限ループを避ける為に入れてあります。 もし、配列の全ての組み合わせが1であれば、永遠に0を探し続けてしまうからです。 ですので、上記の場合なら50回やってBINGO(A,B)=0が見つからなければ、あきらめて終わりにすると言う意味です。 ですので、 If i > 50 Then の50と言う数字が適切かどうかは判りません。 なぜなら、50個の組み合わせのうち49個の組み合わせが1の場合、残りの1個の組み合わせが50回の乱数実行で出るとは限らないからです。 その辺りは、確率論の話になりそうなので、教育-数学でスレを立ててみてください。

  • Werner
  • ベストアンサー率53% (395/735)
回答No.7

#2です。 > 参考URLに行ってみたんですが、シャッフルする際は参考URLのところにも書いてあったようにArray関数を使わないといけないですか? ん?参考URLのarrayはシャッフル対象の配列ですよ。(関数じゃないです。) >> 1. 1番目の要素と、1~6番目(乱数)の要素を入れ替え。 > 最初の1番目の要素は乱数ではないんですよね?ということは、最初に配列r(6)として、この6つの配列に何か数字を入れないといけないということでしょうか? どの要素も乱数ではないです。(乱数をシャッフルしたいなら乱数で良いけど、乱数ならもうシャッフル必要ない…。) シャッフルするのですから要素はシャッフル前に準備しておきます。 今回の場合は1~6の数値を入れておけばよいでしょう。 乱数は何番目の要素と入れ替えるかを決定するために使います。 > 図付きで説明してあったのでなんとなく何が起こっているのかは分かるんですが、 とりあえず具体的にコードのどこで何をしているのかが分かるようにしましょう。 (コードを目でたどってみたり、実際に実行させてみるなどして) > この場合1~6までの乱数を発生させているので、このnは6なのかなって思っています。 その本ではどこかでnに6を代入していたのかもしれませんが、 少なくともこの質問で提示されたコード内にはnに何かを代入しているところはないです。 どこかでちゃんとnに6を代入していますか?

kuru0338
質問者

お礼

>どこかでちゃんとnに6を代入していますか? 言われてみればそうです…このプログラムではどこにもnは入れてないですね…。 シャッフルについてですが、Wernerさんの解説だと私の組んだプログラムのr(6) = Int(Rnd * 6 + 1)はおかしいですね。シャッフルをするとしたら、r(6)には要素を入れて、何番目かということ(私のではiとjにあたると思いますが)を乱数にすべきですね。 すごくわかりやすい説明でした。 ありがとうございます。 意見を参考にして少し自分で組んでみます。

回答No.6

参考でBINGOの抽選サンプルを書いてみました。 Private BINGO(5, 10) As Integer Private Sub Command1_Click() Dim A As Integer Dim B As Integer Dim C As String Dim i As Integer BINGO(0, 0) = 1 Do While BINGO(A, B) = 1 i = i + 1 A = Int(Rnd * 5) + 1 B = Int(Rnd * 10) + 1 Select Case A Case 1 C = "B-" Case 2 C = "I-" Case 3 C = "N-" Case 4 C = "G-" Case 5 C = "O-" End Select If i > 50 Then MsgBox ("END") Exit Sub End If Loop Text1.Text = C & B BINGO(A, B) = 1 End Sub

kuru0338
質問者

お礼

わざわざありがとうございます。 BINGO(5, 10)なので、5行10列のビンゴカードですよね? BINGO(0, 0) = 1とBINGO(A, B) = 1は初期値に戻しているのでしょうか…本当に初心者でごめんなさい。

  • don_go
  • ベストアンサー率31% (336/1059)
回答No.5

n の値及び範囲は何ですか?

kuru0338
質問者

お礼

実は、このFor文のあたりは本に書いてあったのを持ってきたので、私自体このnがなんなのかすらわかっていないんです…。 図付きで説明してあったのでなんとなく何が起こっているのかは分かるんですが、この場合1~6までの乱数を発生させているので、このnは6なのかなって思っています。

  • don_go
  • ベストアンサー率31% (336/1059)
回答No.4

>r(6) = Int(Rnd * 6 + 1) '1~6までの乱数発生 1~6までの乱数を発生させるなら... r(6) = Int(Rnd * 6) + 1 ↑の様にするのが定石です。 ところで... >サイコロを振って、一度出た目はもう出ないような >ゲーム との事ですが、上記の条件だと6回目には、何が出るか プレイヤーに判ってしまいますが、それでゲームとして 成立するのでしょうか?

kuru0338
質問者

お礼

>6回目には何が出るかプレイヤーに判ってしまいます 確かにそうです。 ゲームと呼ぶべきものではないのですが…目的は、最後には一つしか出る目が残らないなのです。 私個人で作っているのではなく、VBの授業の課題なので…申し訳ないです。

  • STICKY2006
  • ベストアンサー率29% (1536/5269)
回答No.3

こんちくわ~。 んー。。どこからツッコミましょうかねぇ。。。?(汗 とりあえず、デバッグ。。。って知ってますか? まず >>としてしまうと全てに0が表示され、結果が表示されません。 当然です。。。あなたの作ったfor文は全て1度も通りませんので。。。 for文が3つあると思いますが、3つとも、一度も通りません。判定文で弾かれます。 もし、弾かれずにfor文の中を通ってもー。。 途中で用意した配列数よりも数が大きくなってあふれエラーになっちゃいます。。。 とりあえず、「全てにおいて0が表示され結果が表示されない」 のは配列の中に数字が入っていないから。という答えになります。 他の部分に関しては、そこが直った段階で。。。ですかね。 とりあえず、直して~からって事で補足要求~です。

kuru0338
質問者

お礼

的確なご意見ありがとうございます。 >配列の中に数字が入っていないから というのはランダムで数字を発生することで数字を各配列に入れているということにはならないですか? この文だと全ての配列に数字を入れないと通らないということなのでしょうか?

  • Werner
  • ベストアンサー率53% (395/735)
回答No.2

「シャッフル」すればよいと言うのはその通りだと思いますが、 1000回も繰り返す必要はないと思います。 要素数6なら以下の手順で5回のループで良さそうです。 1. 1番目の要素と、1~6番目(乱数)の要素を入れ替え。 2. 2番目の要素と、2~6番目(乱数)の要素を入れ替え。 (中略) 5. 5番目の要素と、5~6番目(乱数)の要素を入れ替え。

参考URL:
http://ray.sakura.ne.jp/tips/shaffle.html
kuru0338
質問者

お礼

参考URLに行ってみたんですが、シャッフルする際は参考URLのところにも書いてあったようにArray関数を使わないといけないですか? >1. 1番目の要素と、1~6番目(乱数)の要素を入れ替え。 最初の1番目の要素は乱数ではないんですよね?ということは、最初に配列r(6)として、この6つの配列に何か数字を入れないといけないということでしょうか?

noname#62235
noname#62235
回答No.1

1~6をランダムに並べ替えた順列を得たいということですよね? 一番手っ取り早いのは「シャッフル」することです。 1~6が格納された配列を用意して、1~6の乱数を2個発生させ、それぞれの中身を入れ替える、これを1000回くらい繰り返せば、1~6をランダムに並べ替えた順列が得られますよ。

kuru0338
質問者

お礼

早く回答して頂いたのにも関わらず、お礼が遅くなって申し訳ございません。 >1~6の乱数を2個発生させ、それぞれの中身を入れ替える ソートのような感じでしょうか? それぞれの中身を入れ替えて、一度出たものは捨てる といった感じでしょうか?

関連するQ&A

  • 乱数で・・・

       ラベル10枚に1~10までを乱数を入れたいのです ただしダブらない どうすればいいのでしょうか?? 自分で考えたのですがバグがあります ※コマンドをクリック ※クローンは用意済み Private Sub Command1_Click() Dim a(0 To 9) For i = 0 To 9 a(i) = Int(Rnd * 10)+1  For b = 0 To 9   If a(i) = a(b) Then     If i <> b Then     a(i) = Int(Rnd * 10) + 1     End If   End If   Next b Next i For c = 0 To 9 Label1(c).Caption = a(c) Next c End Sub バグの原因はなんとなくわかるのですがどうすればいいのか分かりません 素人ですいません。

  • 重複しない乱数整数を発生させる。

    重複しない乱数整数を発生させるため、次のような構文を作りましたが、うまくいきません。 アドバイスをお願いします。 Sub RRR() Dim A, B, C, D, E As Integer A = 1 B = 10 For D = A To B Randomize E = Int((B - A + 1) * Rnd + A) Cells(D, 1) = E Next D End Sub

  • VBAの乱数について質問

    乱数 x (0<x<1)を0.1刻みで発生させたいんですが うまくいきません。 プログラム例 Sub 一様乱数() Dim bin#(10) n = 1000 For m = 1 To 10 bin#(m) = 0 Next m For J = 1 To n x = Rnd(1) ix = Int(10 * Rnd(1)) bin#(ix) = bin#(ix) + 1 Next J Cells(4, 1) = " I" Cells(4, 2) = "Bin#(I)度数分布" For I = 0 To 10 Cells(I + 5, 1).Value = I Cells(I + 5, 2).Value = bin#(I) Next I End Sub ここで、9行目ix = Int(10 * Rnd(1))で0.1刻みになり 15行目のFor I = 0 To 10を0 to 1に変えればできると思ったんですが できませんでした。 どこが問題なのかヒントでもいいので教えてください。

  • 乱数の発生 Randomizeを入れた方が良いのか

    VBAについて教えてください。 --------------------------- Sub Randomizeを入れた場合() Dim intMax As Integer Dim intMin As Integer Randomize intMin = 1 intMax = 10 Debug.Print Int((intMax - intMin + 1) * Rnd + intMin) End Sub --------------------------- Sub Randomizeを入れていない場合() Dim intMax As Integer Dim intMin As Integer intMin = 1 intMax = 10 Debug.Print Int((intMax - intMin + 1) * Rnd + intMin) End Sub --------------------------- 上記二つのマクロを実行しても 同じような結果が得られる気がするのですがRandomizeは必要なのでしょうか? 一つのサブプロシージャーの中で1回しか乱数を発生させないのなら Randomizeを使って乱数を初期化する必要はないのですか?

  • VB2010 コードの意味を教えてほしいです。

    VB2010を使って、基礎から勉強中です。 テキストに紹介してあるサンプルプログラムを作っているところですが、 どうしても、わからないところがあります。 乱数を発生させ、こんばんはという文字を、5つのボタンにランダムに表示させて ボタンをクリックして、なんという言葉か当てるゲームです。 その中で、For ~ Nextの中に入力されている内容の意味を 詳しく知りたいです。よろしくお願いします。 Public Class Form1 Private answer As String = "こんばんは" '答え Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load '答えを文字列の配列に変換 Dim moji() As Char = answer.ToCharArray() '文字入れ替え Dim rnd As New Random() '乱数を発生させる For i As Integer = 1 To 10 Dim n1 As Integer = rnd.Next(5) Dim n2 As Integer = rnd.Next(5) Dim m As Char = moji(n1) moji(n1) = moji(n2) moji(n2) = m Next Button1.Text = moji(0) Button2.Text = moji(1) Button3.Text = moji(2) Button4.Text = moji(3) Button5.Text = moji(4) '回答欄を初期化 Label2.Text = "" End Sub Private Sub btns_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click, Button2.Click, Button3.Click, Button4.Click, Button5.Click Dim btn As Button = CType(sender, Button) Label2.Text &= btn.Text btn.Visible = False If Label2.Text = answer Then MsgBox("おめでとう", 0, "正解") ElseIf Label2.Text.Length >= answer.Length Then MsgBox("残念!", 0, "不正解") End If

  • VBで作成した、プログラムについて

    VBで作成した、プログラムについて VBで作成したプログラムをCで作り直したいです。 ソース(フォーム1ロードから、エンドクラスまで)を下記に記載しておきますので、疑問に答えていただけませんか。 ソース: Dim hensu(3, 4) As Integer Dim goukei, i, j As Integer hensu(0, 0) = 20 hensu(0, 1) = 70 hensu(0, 2) = 60 hensu(0, 3) = 30 hensu(0, 4) = 40 hensu(1, 0) = 30 hensu(1, 1) = 50 hensu(1, 2) = 30 hensu(1, 3) = 90 hensu(1, 4) = 40 hensu(2, 0) = 90 hensu(2, 1) = 20 hensu(2, 2) = 80 hensu(2, 3) = 60 hensu(2, 4) = 20 hensu(3, 0) = 40 hensu(3, 1) = 30 hensu(3, 2) = 30 hensu(3, 3) = 60 hensu(3, 4) = 30 label1.text="" For j = 0 to 4 goukei=0 For i = 1 to 3 goukei = goukei + hensu(i, j) Next label1.text=label1.text & goukei & "," Next End Sub End Class 疑問1 forループの部分は、for(j=0; j<5; j++) { } と、 for(i=1; j<4; j++) { } でいいでしょうか。 疑問2 goukei = goukei + hensu(i,j) はどのように記載すれば、よいでしょうか? 疑問3 label1.text=label1.text & goukei & "," の部分は、どのように記載すればよいでしょうか? 疑問4 hensu(0, 0)=20・・・hensu(3, 4)=30 はどう記載すればよいでしょうか? くだらないかもしれませんが、お早めによろしくお願いします。

  • 1+(1+2)+(1+2+3)....+(1+2+...+N)の計算式をVBで・・

    表すにはどうしたらいいでしょうか。 もう3時間くらい格闘しているのですが、 答えを出せません。 Dim S AS LONG DIm N As Integer Dim i As Integer N = Val(TextBox1.Text) S = 0 i = 1 For i = 1 To N Step 1 S = S + i Next Label4.Text = Format(S, "#,##0") で、1+2+3+...+Nはいけるのですが、 上記の式は、Nが1づつ増えていくにしたがって、 Sの値が1 4 10 20 ...となっていくために、…。 どなたか、回答していただける方がおりましたら、 非常に助かります。 よろしくお願いいたします。。

  • VBA AからZで乱数を発生させたい

    Sub AからZで乱数を発生させる() Dim 最大値 As Integer Dim 最小値 As Integer Randomize 最小値 = 1 最大値 = 10 Debug.Print Int((最大値 - 最小値 + 1) * Rnd + 最小値) End Sub --------------------------------------------------------- これを実行すると、1から10の間で乱数を発生させられるのですが、 AからZの間で乱数を発生させたい場合は、 このコードをどのようにすればいいでしょうか? アドバイスよろしくお願いします。

  • Excel VBAライフゲーム

    ExcelのVBAでライフゲームを作りたいのですが、次のプログラムの途中以降がわかりません。 もしよろしければ、このつづきの簡単な実行できるVBAライフゲームを教えてください。 続きのプログラムを教えていただけたら幸いです。 Option Explicit Const ALIVE As Integer = 1 Const DEAD As Integer = 0 Const SIZE As Integer = 19 Const Tmax As Integer = 100 Dim C(SIZE, SIZE) As Integer Sub LifeGame() Dim InitRate As Single Dim T As Integer Dim N As Integer Dim Cnext(SIZE, SIZE) As Integer Dim I As Integer, J As Integer InitRate = -1 Do While InitRate < 0 Or 1 < InitRate Loop For I = 0 To SIZE For J = 0 To SIZE If Rnd() < InitRate Then C(I, J) = ALIVE Else C(I, J) = DEAD End If Next J Next I For T = 1 To Tmax For I = 0 To SIZE For J = 0 To SIZE If C(I, J) = ALIVE Then Cells(I + 1, J + 1).Value = "■" Else Cells(I + 1, J + 1).Vallue = "" End If Next J Next I For I = 0 To SIZE For J = 0 To SIZE N = Count(I, J) Next J Next I For I = 0 To SIZE For J = 0 To SIZE C(I, J) = Cnext(I, J) Next J Next I Next T End Sub Function Count(I As Integer, J As Integer) As Integer End Function

  • EXCEL VBA 配列変数の値すべてを返すには

    EXCELは2002ですが、97でも動くと嬉しいです。 《質問》 1~10をランダムに並べるためのプログラムを書きました。 これはこれで動くのですが、一行(3行目)だではなく 4行目にも、5行目にも同じことをしたい場合、 バブルソートの部分をサブルーチン(関数)にしたいのですが X_v() = GetSortArray(n_s,n_v)()とはできません。.cloneもだめですよね。 かといって、要素毎に引くとその度にRndが効いて、1~10が並びません。 どのようにやるのが、スマートなのでしょうか?よろしくお願いします。 《以下プログラム》 Sub Bu_Click() Dim i As Integer Dim j As Integer Const n_e = 10 Const n_s = 1 Dim X_r(n_e) As Long Dim X_v(n_e) As Long Dim temp1 As Long Dim temp2 As Integer Randomize For i = n_s To n_e X_r(i) = Int(Rnd * 10 ^ 9) X_v(i) = i Next i For i = n_s To n_e - 1 For j = n_s To n_e - 1 If X_r(j + 1) < X_r(j) Then temp1 = X_r(j + 1) X_r(j + 1) = X_r(j) X_r(j) = temp1 temp2 = X_v(j + 1) X_v(j + 1) = X_v(j) X_v(j) = temp2 End If Next j Next i For i = 0 To n_e - 1 Cells(3, 3 + i).Value = X_v(i + 1) Next i End Sub Public Function GetSortArray(s As Integer, e As Integer) As Long() Dim r() As Long Dim v() As Long Dim temp1 As Long Dim temp2 As Integer ReDim r(e) ReDim v(e) Randomize For i = s To e r(i) = Int(Rnd * 10 ^ 9) v(i) = i Next i For i = s To e - 1 For j = s To e - 1 If r(j + 1) < r(j) Then temp1 = r(j + 1) r(j + 1) = r(j) r(j) = temp1 temp2 = v(j + 1) v(j + 1) = v(j) v(j) = temp2 End If Next j Next i GetSortArray = v() End Function ありゃ?Tabのスペース消えますね。

専門家に質問してみよう