クラスモジュールとコレクションを使ったゲームを作りたいですけど..


TAKU  2002-09-03 13:01:24  No: 104804  IP: [192.*.*.*]

今、大学のプロジェクトの一環で、クラスモジュールとコレクションを利用したBINGOゲームを作ろうかと思っています。が、初心者な自分はクラスモジュールとコレクションがイマイチ分りません。詳しく説明したサイトなど有りましたら教えていただきたいな思います。参考になるサンプルソースの紹介などあったら最高です。
ゲームの概略は
縦列と横列のマスの数をテキストボックスで入力(例、縦4マス横5マスとか)
各マスにランダムで1〜99までの数字を配列(arrayかな?)
コマンドボタンで、ランダムに番号を抽出
該当すればコレクションに収めて、縦もしくは横が揃えばBINGO!
全部のマスが埋まるまで、継続して全部の数が揃えばフルハウス!
ゲーム終了
注意、番号抽出はランダムで、当然二度と同じ番号は出てはいけない。

長くなりましたが、宜しくお願いします。

編集 削除
たかみちえ  URL  2002-09-03 13:37:53  No: 104805  IP: [192.*.*.*]

> 初心者な自分はクラスモジュールとコレクションがイマイチ分りません。
  参考になるかも。わたしは最初、読んでもわかりませんでしたけどね^^;
http://homepage1.nifty.com/CavalierLab/lab/vb/clsmdl/
  コレクションは、要素の名前に、
文字列をつけられるぐらいで、配列と大差はなかったと思います。
サンプルもあんまり見かけませんね。
配列の使い方がわかれば、問題ないということでしょうか?

> 注意、番号抽出はランダムで、当然二度と同じ番号は出てはいけない。
  この方法は正攻法じゃないと思いますけど、わたしはこんな方法でやりました。

1.ランダムで数字を出す。その数字を、文字列にして用意した変数に追加
2.区切り文字を文字列変数に追加
3.新しい数字を出したときに、文字列を検索して、重複があったらやり直し

  こんな感じです。
文字列変数に、1が出たら"1|"、次2がでたら、それに追加して"1|2|"
とやっていって、
ランダムで数字を出すたびに、この変数の中に、それと同じものが含まれているかどうかを調べます。
もしあったら、もう一度ランダムで数字を出しなおします。

  こんなのでどうでしょうか?

編集 削除
YuO  2002-09-03 16:51:26  No: 104806  IP: [192.*.*.*]

> 注意、番号抽出はランダムで、当然二度と同じ番号は出てはいけない。

シャッフルですね。
古典ですが,
Dim array(1 To 99) As Integer
Dim i As Integer, j As Integer, Temp As Integer

' 初期化
For i = 1 To 99
    array(i) = i
Next i

' シャッフル
For i = 1 To 99
    j = Int(Rnd() * 99) + 1 ' 数値をひとつ選ぶ
    '入れ替え
    Temp = array(j)
    array(j) = array(i)
    array(i) = Temp
Next i
なんてのはどうでしょう。

編集 削除
あんちゃん  2002-09-03 18:28:41  No: 104807  IP: [192.*.*.*]

コレクションの例(固定値の場合)

  Const 値_01 as Long = 128
  Const 値_02 as Long = 256
  Const 値_03 as Long = 512
  Const 値_04 as Long = 4096512

  Dim Myクラス as New 自作クラス
  
  Dim col As Collection
  Dim itm As Variant
    
    Set col = New Collection    ’コレクションの追加
    col.Add 値_01
    col.Add 値_02
    col.Add 値_03
    col.Add 値_04
    
    For Each itm In col         ’コレクションの中身を取り出しつつ、クラス側で別処理
      Call Myクラス.NEW_SET_NAME(設定_01, 設定_02, 設定_03, _
                                 設定_04, itm, "CODE1")
    Next
    

    Set col = Nothing           ’コレクションの開放(コレやらないと値が残ります)
    Set Myクラス = Nothing


コレクションが変動値の場合は、ForやDoで値の入力可

編集 削除
TAKU  2002-09-03 23:46:15  No: 104808  IP: [192.*.*.*]

皆さんお早いアドバイスありがとうございます。
追加項目をここであげたいなと思います。

1.縦マスの数1〜4まで、横マスの数1〜5まで、テキストボックスにプレイヤーが入力して、コマンドボタンでBINGOカードを随時作成するのですが、何と!一つのラベルの中に、個々の数字を配列していかなくてはなりません.....これも課題のうちの一つで、簡単に表示する方法はありませんか?

例)縦3、横3とテキストボックスに入力した場合
3×3で合計9マスのカードが作成されます。この9マスの中に数字を入れていき、一つのラベルに表示しなければなりません....

3    45    56
76  82    98
16  34    50

こんな感じにラベル一つに表示させるにはどうしたらよいのでしょうか?


2、クラスモジュールは全部で3つになり構成されなくてはなりません。
    一つ目はBingoCard=CheckCall(Value)AnyLineCovered()CardCovered()
    二つ目はBingoLine=CheckCall(Value)LineCovered()
    三つ目はBingoNumber=CheckCall(Value)

こんな感じになります。
この場合、どこのクラスモジュールに、Arrayやコレクションを持っていけばよいのか分りません。
かなり込み入った内容になりますが、ご指導の程お願いします。

編集 削除
あんちゃん  2002-09-04 10:14:21  No: 104809  IP: [192.*.*.*]

>一つのラベルに表示
 Dim Name_01, Name_02, Name_03 As String
 Name_01 = Text1.Text & "   " & Text11.Text
 Name_02 = Text2.Text & "   " & Text22.Text
 Name_03 = Text3.Text & "   " & Text33.Text
 
 Label1.Caption = Name_01 & vbCrLf & Name_02 & vbCrLf & Name_03

>どこのクラスモジュールに、Arrayやコレクションを持っていけばよいのか
作り手の自由だと思いますが?
まず、クラスの役割を理解しなければ答えは出ないかと思います。
BingoCard、BingoLine、BingoNumber
それぞれに何をさせるべきなのか考えましょう。

編集 削除
TAKU  2002-09-04 12:34:03  No: 104810  IP: [192.*.*.*]

あんちゃんさま、アドバイスありがとう御座います。
BINGOカードを作るコマンドボタンのソースを自分なりに作ってみましたが、
いまいちアドバイスの内容が分りません……Text11?Text22?Text33?
以下に記しますんで、Label1.Captionの所にどうやったら、該当する数字全部を綺麗に並べることが出来るのでしょうか??
すみませんアドバイスお願いします。

Private Sub Command1_Click()
Dim intNum As Integer

If Not IsNumeric(Text1) Then
        MsgBox "数字1〜4を入力して下さい", vbOKOnly, "error"
        Exit Sub
End If

If Not IsNumeric(Text2) Then
        MsgBox "数字1〜5を入力して下さい", vbOKOnly, "error"
        Exit Sub
End If

If (Val(Text1.Text) <= 4) And (Val(Text2.Text) <= 5) Then
    mintLaw = Val(Text1.Text)
    mintCol = Val(Text2.Text)
    intNum = mintLaw * mintCol
    
    Dim ary(1 To 99) As Integer
Dim i As Integer, j As Integer, Temp As Integer

' 初期化
For i = 1 To 99
    ary(i) = i
Next i

' シャッフル
For i = 1 To intNum
    j = Int(Rnd() * 99) + 1 ' 数値をひとつ選ぶ
    '入れ替え
    Temp = ary(j)
    ary(j) = ary(i)
    ary(i) = Temp
    Label1.Caption = ary(i)
Next i

編集 削除
あんちゃん  2002-09-04 15:13:48  No: 104811  IP: [192.*.*.*]

Label1.Caption = ary(i)を以下のように書き換えるのはいかがでしょう?



Dim 出力用 As String

    if i mod 3 then
       出力用 = 出力用 & ary(i) & vbcrlf
    else
       出力用 = 出力用 & ary(i) & "   "     '  "   "はスペース
    end if
Next i

   Label1.Caption = 出力用

編集 削除
TAKU  2002-09-04 23:33:53  No: 104812  IP: [192.*.*.*]

あんちゃんさま、返信ありがとう御座います。

アドバイス通り自分なりにやってみたのですが、あんちゃんさまのプログラムだと、縦に数字が並んでいき一定の数(3)になると、次の列に数字が並ぶようになってるみたいですが、実際は3の次に1個だけが横に並んで、次の数字からは一列目の下に並んでしまいます.....

縦マス3、横マス3と指定した場合

70
56
58  45
88
34
22  14
35
こんな感じになってしまいます.....


今度は自分なりにあんちゃんさんのプログラムを改善して、横列に数字を並べていき、一定の数(テキストボックスに入力された横マスの数)になったら、下の列に改行していく方法にしました。そこで問題が発生しました。
例えば縦3、横3にした場合、最初の横マス3は(i)から取得できるのですが、次の3個目(プログラム上は6)の取得が出来ません。つまり2列目の折り返しが出来ないのです。

70  58  56
34  78  24  13  59  23  

となってしまいます.....
この場合、どういうふうにすればいいのでしょうか??

プログラムは以下のとうりです。


Private Sub Command1_Click()
Dim intNum As Integer
'Dim i As Integer
Dim 出力用 As String

If Not IsNumeric(Text1) Then
        MsgBox "Please enter a number for the raws", vbOKOnly, "error"
        Exit Sub
End If

If Not IsNumeric(Text2) Then
        MsgBox "Please enter a number for the column", vbOKOnly, "error"
        Exit Sub
End If

If (Val(Text1.Text) <= 4) And (Val(Text2.Text) <= 5) Then
    mintLaw = Val(Text1.Text)
    mintCol = Val(Text2.Text)
    intNum = mintLaw * mintCol
    
    Dim ary(1 To 99) As Integer
Dim i As Integer, j As Integer, Temp As Integer

' 初期化
For i = 1 To 99
    ary(i) = i
Next i

' シャッフル
For i = 1 To intNum
    j = Int(Rnd() * 99) + 1 ' 数値をひとつ選ぶ
    '入れ替え
    Temp = ary(j)
    ary(j) = ary(i)
    ary(i) = Temp

    If i = mintLaw Then
       出力用 = 出力用 & ary(i) & vbCrLf
    Else
       出力用 = 出力用 & ary(i) & "   "     '  "   "はスペース
    End If

   Label1.Caption = 出力用

Next i

Else
MsgBox "The number is error"
Exit Sub
End If

End Sub

編集 削除
TAKU  2002-09-05 00:09:53  No: 104813  IP: [192.*.*.*]

自分なりにこうやってみましたがどうでしょうか?

For i = 1 To intNum
    j = Int(Rnd() * 99) + 1 ' 数値をひとつ選ぶ
    '入れ替え
    Temp = ary(j)
    ary(j) = ary(i)
    ary(i) = Temp
    'Label1.Caption = ary(i)

    If i = mintLaw Or i = mintLaw * 2 Or i = mintLaw * 3 Or i = mintLaw * 4 Then
       出力用 = 出力用 & ary(i) & vbCrLf
    Else
       出力用 = 出力用 & ary(i) & "   "     '  "   "はスペース
    End If


   Label1.Caption = 出力用

Next i

編集 削除
TAKU  2002-09-05 00:44:58  No: 104814  IP: [192.*.*.*]

今度はBINGOカードの中の数字をコレクションに入れていきたいのですが、ここで分らないのが、コレクションの中に入れた数字に対して、横列が揃った場合BINGOになるのですが、横列は2〜5まで条件が変わります。どうしたらランダムに抽出した数字をプログラム上で確認しながらBINGOを確定させる事が出来るのでしょうか?
宜しくお願いします。

編集 削除
あんちゃん  2002-09-06 11:46:10  No: 104815  IP: [192.*.*.*]

訂正

Dim 出力用 As String

    if i mod 3 = 0 then
       出力用 = 出力用 & ary(i) & vbcrlf
    else
       出力用 = 出力用 & ary(i) & "   "     '  "   "はスペース
    end if
Next i

   Label1.Caption = 出力用

編集 削除
あんちゃん  2002-09-06 14:05:07  No: 104816  IP: [192.*.*.*]

>ランダムに抽出した数字をプログラム上で確認
□□□        <−−イメージはこんな感じでしょうか
□□□
□□□

□□
□□

3×3、2×2の場合(それ以外も)でも
配列やコレクションの位置から
構造を取得するのは可能です。

配列と変数を使えば出来ますよ。

編集 削除
TAKU  2002-09-06 20:39:12  No: 104817  IP: [192.*.*.*]

あんちゃんさま返信ありがとう御座います。
イメージはまったくその通りです!
そのイメージの横列のみ、確認していき一つでも列が揃えばBINGOです。さらにゲームは継続され、全部の数字が揃えばフルハウスで、ゲーム終了になります。

配列と変数を使えば出来るとの事ですが、具体的な例を上げていただけないでしょうか?お手数掛けてしまうかもしれませんが、個人的にいきなりこのようなプログラムの課題を受けてしまい、一人苦労しています……

編集 削除
あき☆彡  2002-09-08 15:32:45  No: 104818  IP: [192.*.*.*]

課題は試行錯誤しながら作成するのが大切だと思いますが・・・

具体的なら例です
縦横のチェックはこんな感じに出来ます。
少しテストしただけなので不具合があるかも(;^_^A
コードの解説はしません。
実行して参考になる動きであれば解析してみて下さいm(_ _)m

・使用数字1〜99
・縦横は同じ数字で変更可(2〜9)(初期表示は5)
・ラインは縦横斜め
・縦横が3,5,7,9の場合、真ん中はFree

使用モジュール
フォームモジュール2つ(Form1,Form2)
クラスモジュール2つ(Class1,Class2)

Form1配置コントロール
テキストボックス1つ(Text1)
リストボックス1つ(List1)
コマンドボタン2つ(Command1,Command2)

**********Form1コード**********
Option Explicit
Private clsNo As Class1
Private clsBingoForm As Class2
Private colBingoForms As Collection

Private Sub Command1_Click()
    For Each clsBingoForm In colBingoForms
        If Text1.Text Like "[2-9]" Then clsBingoForm.RowCol = CLng(Text1.Text)
        clsBingoForm.SheetChange
    Next clsBingoForm
    clsNo.Clear
    List1.Clear
End Sub

Private Sub Command2_Click()
    Dim lNo As Long
    lNo = clsNo.GetNo
    If lNo > 0 Then
        List1.AddItem Format(lNo, "@@@")
        List1.ListIndex = List1.ListCount - 1
        List1.Refresh
        For Each clsBingoForm In colBingoForms
            clsBingoForm.AddNo lNo
        Next clsBingoForm
    End If
End Sub

Private Sub Form_Load()
    Set clsNo = New Class1
    Set colBingoForms = New Collection
    Call Init
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Dim i As Long
    For i = 1 To colBingoForms.Count
        colBingoForms.Remove 1
    Next i
    Set colBingoForms = Nothing
    Set clsNo = Nothing
    Set Form1 = Nothing
End Sub

Private Sub Init()
    Dim i As Long
    Me.Move 0, 0, 2000, 2000
    List1.Move 0, 0, 600, 1500
    Text1.Move List1.Left + List1.Width, 0, 1200, 500
    Command1.Move List1.Left + List1.Width, Text1.Top + Text1.Height, 1200, 500
    Command2.Move List1.Left + List1.Width, Command1.Top + Command1.Height, 1200, 500
    Text1.Text = 5
    Command1.Caption = "シート変更"
    Command2.Caption = "番号取得"
    For i = 0 To 3
        Set clsBingoForm = New Class2
        clsBingoForm.Show
        clsBingoForm.Move 3500 * i, Me.Top + Me.Height, 3500, 3000
        colBingoForms.Add Item:=clsBingoForm, Key:=CStr(i)
        Set clsBingoForm = Nothing
    Next i
End Sub

**********Class1コード**********
Option Explicit
Private mbNoFlg(1 To 99) As Boolean
Private mlNoCnt As Long

Property Get GetNo() As Long
    Dim lNo As Long
    GetNo = 0
    If mlNoCnt >= 99 Then Exit Property
    Randomize
    Do
        lNo = Int((99 * Rnd) + 1)
    Loop Until Not mbNoFlg(lNo)
    mbNoFlg(lNo) = True
    mlNoCnt = mlNoCnt + 1
    GetNo = lNo
End Property

Public Sub Clear()
    mlNoCnt = 0
    Erase mbNoFlg
End Sub

**********Class2コード**********
Option Explicit
Private mlNo() As Long
Private mlColor() As Long
Private mbFlg() As Boolean
Private mlRowCol As Long
Private mlLineCnt As Long
Private WithEvents mFrm As Form

Public Sub Show()
    Set mFrm = New Form2
    mFrm.Show
End Sub

Public Sub Move(lLeft As Single, lTop As Single, lWidth As Single, lHeight As Single)
    If IsForm Then mFrm.Move lLeft, lTop, lWidth, lHeight
End Sub

Public Sub AddNo(lNo As Long)
    If IsForm Then Call sCheckNo(lNo)
End Sub

Property Let RowCol(lRowCol As Long)
    If 1 < lRowCol And lRowCol < 10 Then mlRowCol = lRowCol
End Property

Public Sub SheetChange()
    mlLineCnt = 0
    ReDim mlNo(1 To mlRowCol, 1 To mlRowCol)
    ReDim mbFlg(1 To mlRowCol, 1 To mlRowCol)
    ReDim mlColor(1 To mlRowCol, 1 To mlRowCol)
    Call sSheetClear
    Call sDsp
End Sub

Private Sub sCheckNo(lNo As Long)
    Dim bMatch As Boolean
    Dim i&, j&
    mlLineCnt = 0
    bMatch = False
    For i = 1 To mlRowCol
        For j = 1 To mlRowCol
            If mlNo(i, j) = lNo Then bMatch = True
            If bMatch Then Exit For
        Next j
        If bMatch Then Exit For
    Next i
    If Not bMatch Then Exit Sub
    mbFlg(i, j) = True
    mlColor(i, j) = vbBlue
    Call sLineCheck
    Call sDsp
End Sub

Private Sub sLineCheck()
    Dim bVertical As Boolean
    Dim bHorizontal As Boolean
    Dim bOblique1 As Boolean
    Dim bOblique2 As Boolean
    Dim i&, j&

    bOblique1 = True
    bOblique2 = True
    For i = 1 To mlRowCol
        bVertical = True
        bHorizontal = True
        For j = 1 To mlRowCol
            If Not mbFlg(i, j) Then bVertical = False
            If Not mbFlg(j, i) Then bHorizontal = False
        Next j
        If bVertical Then mlLineCnt = mlLineCnt + 1
        If bHorizontal Then mlLineCnt = mlLineCnt + 1
        For j = 1 To mlRowCol
            If bVertical Then mlColor(i, j) = vbRed
            If bHorizontal Then mlColor(j, i) = vbRed
        Next j
        If Not mbFlg(i, i) Then bOblique1 = False
        If Not mbFlg(i, mlRowCol - (i - 1)) Then bOblique2 = False
    Next i
    If bOblique1 Then mlLineCnt = mlLineCnt + 1
    If bOblique2 Then mlLineCnt = mlLineCnt + 1
    For i = 1 To mlRowCol
        If bOblique1 Then mlColor(i, i) = vbRed
        If bOblique2 Then mlColor(i, mlRowCol - (i - 1)) = vbRed
    Next i
End Sub

Private Sub sSheetClear()
    Dim clsNo As Class1
    Dim i&, j&
    Set clsNo = New Class1
    For i = 1 To mlRowCol
        For j = 1 To mlRowCol
            mlNo(j, i) = clsNo.GetNo
        Next j
    Next i
    If mlRowCol Mod 2 = 1 Then
        i = mlRowCol \ 2 + 1
        mlNo(i, i) = -1
        mbFlg(i, i) = True
        mlColor(i, i) = vbGreen
    End If
    Set clsNo = Nothing
End Sub

Private Sub sDsp()
    Dim i&, j&
    If Not IsForm Then Exit Sub
    mFrm.Cls
    For i = 1 To mlRowCol
        For j = 1 To mlRowCol
            mFrm.ForeColor = mlColor(i, j)
            mFrm.Print IIf(mlNo(i, j) = -1, "Free", Format(mlNo(i, j), "@@@") & Space(1));
        Next j
        mFrm.Print
    Next i
    If mlLineCnt > 0 Then
        mFrm.Print
        mFrm.ForeColor = vbBlack
        mFrm.Print Space(5) & CStr(mlLineCnt) & "ライン"
    End If
    mFrm.Refresh
End Sub

Private Function IsForm() As Boolean
  IsForm = Not (mFrm Is Nothing)
End Function

Private Sub Class_Initialize()
    RowCol = 5
End Sub

Private Sub Class_Terminate()
    If IsForm Then Unload mFrm
End Sub

Private Sub mFrm_Load()
    With mFrm
        .Font.Name = "MS ゴシック"
        .Font.Size = 9
        .AutoRedraw = True
    End With
    Call SheetChange
End Sub

Private Sub mFrm_Unload(Cancel As Integer)
    Set mFrm = Nothing
End Sub

編集 削除
TAKU  2002-09-09 10:37:07  No: 104819  IP: [192.*.*.*]

あき☆彡さん返信ありがとう御座います。
今、一生懸命自分なりに解析してますが、ビンゴカードを作る過程で、Class1とClass2を行き来する文があります。ここでビンゴカードを作っているのだなという事は分かっているのですが、何故?Class1とClass2を行き来させなければいけない理由が分かりません。
この質問で大丈夫でしょうか?
アドバイスお願いします。

Class2のビンゴカードを作るところの文

Private Sub sSheetClear()
    Dim clsNo As Class1
    Dim i&, j&
    Set clsNo = New Class1
    For i = 1 To mlRowCol
        For j = 1 To mlRowCol
            mlNo(j, i) = clsNo.GetNo
        Next j
    Next i
    If mlRowCol Mod 2 = 1 Then
        i = mlRowCol \ 2 + 1
        mlNo(i, i) = -1
        mbFlg(i, i) = True
        mlColor(i, i) = vbGreen
    End If
    Set clsNo = Nothing
End Sub

Class1のビンゴカードを作るところの文

Property Get GetNo() As Long
    Dim lNo As Long
    GetNo = 0
    If mlNoCnt >= 99 Then Exit Property
    Randomize
    Do
        lNo = Int((99 * Rnd) + 1)
    Loop Until Not mbNoFlg(lNo)
    mbNoFlg(lNo) = True
    mlNoCnt = mlNoCnt + 1
    GetNo = lNo
End Property

この文でどうしてClass1とClass2に分ける必要があるのでしょうか?
どうゆうコンセプトの元で、まっさらな白紙の状態からここまでたどり着けるのでしょうか?

編集 削除