電子書籍の厳選無料作品が豊富!

初めて投稿させて頂きます。
サイコロを振って、一度出た目はもう出ないような
ゲームをプログラミングしています。

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が表示され、結果が表示されません。
これについても回答をお願いします。
まだ初心者ですが、よろしくお願いします。

A 回答 (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
    • good
    • 0
この回答へのお礼

わざわざプログラムを組んで頂き、大変感謝しております。

すごくわかりやすかったので、重複しない乱数を発生することが出来ました。ありがとうございます。

あと結果を表示したいのですが、色々やってみているのですがなかなか出来ません。
ボタンをクリックするごとに、所定のテキストに結果を表示していきたいのですが、このプログラムだとANS(A) = 0となっているので結果表示の際ANS(A)は使えないのでしょうか?

お礼日時:2006/06/26 14:08

#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
    • good
    • 0
この回答へのお礼

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

お礼日時:2006/07/05 14:43

>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回の乱数実行で出るとは限らないからです。

その辺りは、確率論の話になりそうなので、教育-数学でスレを立ててみてください。
    • good
    • 0

#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を代入していますか?
    • good
    • 0
この回答へのお礼

>どこかでちゃんとnに6を代入していますか?
言われてみればそうです…このプログラムではどこにもnは入れてないですね…。

シャッフルについてですが、Wernerさんの解説だと私の組んだプログラムのr(6) = Int(Rnd * 6 + 1)はおかしいですね。シャッフルをするとしたら、r(6)には要素を入れて、何番目かということ(私のではiとjにあたると思いますが)を乱数にすべきですね。

すごくわかりやすい説明でした。
ありがとうございます。
意見を参考にして少し自分で組んでみます。

お礼日時:2006/06/25 01:36

参考で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
    • good
    • 0
この回答へのお礼

わざわざありがとうございます。

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

お礼日時:2006/06/24 00:59

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

    • good
    • 0
この回答へのお礼

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

お礼日時:2006/06/24 00:06

>r(6) = Int(Rnd * 6 + 1) '1~6までの乱数発生



1~6までの乱数を発生させるなら...
r(6) = Int(Rnd * 6) + 1
↑の様にするのが定石です。

ところで...
>サイコロを振って、一度出た目はもう出ないような
>ゲーム

との事ですが、上記の条件だと6回目には、何が出るか
プレイヤーに判ってしまいますが、それでゲームとして
成立するのでしょうか?
    • good
    • 0
この回答へのお礼

>6回目には何が出るかプレイヤーに判ってしまいます

確かにそうです。
ゲームと呼ぶべきものではないのですが…目的は、最後には一つしか出る目が残らないなのです。

私個人で作っているのではなく、VBの授業の課題なので…申し訳ないです。

お礼日時:2006/06/24 00:10

こんちくわ~。



んー。。どこからツッコミましょうかねぇ。。。?(汗

とりあえず、デバッグ。。。って知ってますか?


まず
>>としてしまうと全てに0が表示され、結果が表示されません。
当然です。。。あなたの作ったfor文は全て1度も通りませんので。。。
for文が3つあると思いますが、3つとも、一度も通りません。判定文で弾かれます。

もし、弾かれずにfor文の中を通ってもー。。
途中で用意した配列数よりも数が大きくなってあふれエラーになっちゃいます。。。


とりあえず、「全てにおいて0が表示され結果が表示されない」
のは配列の中に数字が入っていないから。という答えになります。

他の部分に関しては、そこが直った段階で。。。ですかね。

とりあえず、直して~からって事で補足要求~です。
    • good
    • 0
この回答へのお礼

的確なご意見ありがとうございます。

>配列の中に数字が入っていないから
というのはランダムで数字を発生することで数字を各配列に入れているということにはならないですか?
この文だと全ての配列に数字を入れないと通らないということなのでしょうか?

お礼日時:2006/06/24 00:02

「シャッフル」すればよいと言うのはその通りだと思いますが、


1000回も繰り返す必要はないと思います。
要素数6なら以下の手順で5回のループで良さそうです。

1. 1番目の要素と、1~6番目(乱数)の要素を入れ替え。
2. 2番目の要素と、2~6番目(乱数)の要素を入れ替え。
(中略)
5. 5番目の要素と、5~6番目(乱数)の要素を入れ替え。

参考URL:http://ray.sakura.ne.jp/tips/shaffle.html
    • good
    • 0
この回答へのお礼

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

お礼日時:2006/06/24 01:03

1~6をランダムに並べ替えた順列を得たいということですよね?


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

早く回答して頂いたのにも関わらず、お礼が遅くなって申し訳ございません。

>1~6の乱数を2個発生させ、それぞれの中身を入れ替える
ソートのような感じでしょうか?
それぞれの中身を入れ替えて、一度出たものは捨てる
といった感じでしょうか?

お礼日時:2006/06/23 23:55

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!