xlSaper   strona główna:
A po co ten Excel ;-)
 
Tak.. Ten sam nudny Saper ;-) Pewnie gdyby poszukać to i nie jeden w Excelu był napisany więc żadna nowość. Jednak potraktowałem  
jak zabawę i chciałby pokazać jak napisać Sapera w Excelu :-)  
  Gra pod poniższym linkiem:
    Choć każdy pewnie w sapera kiedyś grał wypiszmy zadanie które trzeba będzie zrealizować chcąc napisać taką grę.   xlSaper.zip
 - Trzeba stworzyć planszę: X wierszy - Y kolumn. Wartości X i Y trzeba jakoś określić.  
 - Możliwość określenia ilości min na planszy. Domyślnie np.: 15% pól.  
 - Klikając na przycisk tworzymy planszę o określonych parametrach: X, Y i ilość min  
 - W jakiej pozycji na UserForm'em powinna znaleźć się plansza.  
 - Jak losowo rozmieścić miny  
 - Po kliknięciu (Lewy Prz. Myszy) w element planszy program ma prawidłowo zareagować:  
     - jeżeli nie ma miny. Trzeba zliczyć ilość min w sąsiedztwie iw zależności od ilości znalezionych min:  
          - jeżeli min > 0. Kliknięty element musi pokazać tą ilość  
          - jeżeli min = 0. Kliknięty element nic nie zwraca i należy sprawdzić sąsiadów:  
               - jeżeli sąsiad to mina - zostawiamy w spokoju  
               - jeżeli w sąsiedztwie sąsiada jest > 0 min to sąsiad ma zwrócić tą ilość  
               - jeżeli w sąsiedztwie sąsiada nie ma min - sprawdzani są jego sąsiedzi.... I tak dalej...  
     - jeżeli dany element zawiera minę. To odkrywane są wszystkie pola z minami i koniec gry.  
 - Po kliknięciu (Prawy Prz. Myszy) na element znaczymy flagą że wg nas tu znajduje się mina. Kolejne kliknięcie zdejmuje flagę.  
 - Po odkryciu wszystkich pól bez min następuje informacja o zwycięstwie i pokazanie pól z minami.  
 - Trzeba zezwolić na reset gry. Usunięcie planszy i wstawienie nowej o bieżących ustawieniach.  
 - Trzeba zliczać i na bieżąco podawać ilość odkrytych pól i ilość postawionych flag.  
 
    No i sprawa okazuje się nie taka znowu banalna :-) Jednak krok po kroku postaram się wyjaśnić jak podołać tym zadaniom.  
 
Utworzenie Planszy do Gry.  
Uznałem że najlepiej do utworzenia planszy wykorzystać ToggleButton'y a więc przyciski, które mogą pozostać kliknięte. Układane obok  
siebie utworzą planszę. Ile tych ToggleButton'ów trzeba będzie poukładać? No właśnie...  
    Grupę kontrolek dzięki której określimy wymiary planszy oraz ilość min jaka będzie po niej rozstawiona wstawimy do Frame1. Znajdą   
się tam: 3 kontrolki ScrollBar i 3 TextBox'y. ScrollBar1 i ScrollBar2 określimy w oknie Properties Min = 5 i Max = 20. Wskazane wartości  
będą się ukazywały odpowiednio w TextBox1 i TextBox2. Wartości te będą odpowiadać wymiarom planszy. ScrollBar3 będzie określał  
ilość min jaką chcemy rozstawić po planszy. Domyślnie przyjmiemy żeby program proponował 15% wszystkich pól ale ScrollBar'em będzie  
można tę wartość zmienić. Min = 5 ale Max musi być określona programowo np.: (ilość Wierszy * ilość Kolumn) - 5  
W tej grupie wstawimy jeszcze przycisk który utworzy naszą planszę ale również będzie można nim tę planszę Reset'nąć. Dlatego  
również użyjemy ToggleButton'a jednak żeby go odróżnić od reszty wstawianych później elementów planszy nadamy mu właściwość  
Tag = "Start" i wyczyścimy właściwość Caption - będzie on określany programowo.  
    Tę cześć zadania realizujemy procedurami zdarzeniowymi kontrolek i UserForm'a.  
 
Private Sub ScrollBar1_Change()  
    Dim intIlePol As Integer  
    Dim int15proc As Integer  
      
    With Me  
        intIlePol = .ScrollBar1 * .ScrollBar2  
        int15proc = Int(intIlePol * 0.15)  
        .TextBox1 = .ScrollBar1  
        With .ScrollBar3  
            .Max = intIlePol - 5  
            .Value = IIf(.Min > int15proc, .Min, int15proc)  
            Me.TextBox3 = .Value  
        End With  
    End With  
End Sub  
 
Private Sub ScrollBar2_Change()  
    Dim intIlePol As Integer  
    Dim int15proc As Integer  
    With Me  
        intIlePol = .ScrollBar1 * .ScrollBar2  
        int15proc = Int(intIlePol * 0.15)  
        .TextBox2 = .ScrollBar2  
        With .ScrollBar3  
            .Max = intIlePol - 5  
            .Value = IIf(.Min > int15proc, .Min, int15proc)  
            Me.TextBox3 = .Value  
        End With  
    End With  
End Sub  
 
Private Sub ScrollBar3_Change()  
    With Me  
        .TextBox3 = .ScrollBar3  
    End With  
End Sub  
 
Private Sub UserForm_Initialize()  
    With Me  
        .TextBox1 = .ScrollBar1  
        .TextBox2 = .ScrollBar2  
        .TextBox3 = .ScrollBar3  
        .ToggleButton1.Caption = "Start"  
    End With  
End Sub  
 
Trzeba jedynie dodać że TextBox'om została określona właściwość Enabled = False. Nie będzie można jej zmienić inaczej niż poprzez  
odpowiedni ScrollBar.  
    Zaplanowałem że tę grupę kontrolek umieszczę w prawym-dolnym rogu formularza. Plansza zostanie umiejscowiona po lewej stronie.  
I miejsce na nią przeznaczone to kwadrat wielkości max'ymalnej ilości elementów planszy w pionie * (..) w poziomie * wielkość pojedyn-  
czego elementu - ToggleButtona. Przyjmując, że wielkość jednego elementu to 18x18 miejsca na planszę potrzeba 360x360 + trochu  
miejsca na margines i nasza grupa może być wstawiona dalej niż 375 od Lewej krawędzi formy.  
 
Trudniejszy fragment to oprogramowanie przycisku tworzącego planszę. Teraz całość później wyjaśnienia fragmentami. :-)  
 
Private Sub ToggleButton1_Click()  
    Dim i As Integer, j As Integer  
    Dim objTB As MSForms.ToggleButton  
    Dim pozXStart As Single, pozYStart As Single  
    Dim pozX As Single, pozY As Single  
      
    Dim objCtr As MSForms.Control, a As Integer  
    Dim tblM As Variant  
      
    Dim objTBButton As clsTBEvents  
      
    Const sCtrH As Single = 18  
    Const sCtrW As Single = 18  
      
    Const sinTop As Single = 5  
    Const sinHeight As Single = 380  
    Const sinLeft As Single = 5  
    Const sinWidth As Single = 380  
      
    If Me.ToggleButton1 Then  
        With Me  
            iW = CInt(.TextBox1)  
            iK = CInt(.TextBox2)  
            iM = CInt(.TextBox3)  
        End With  
          
        pozXStart = (sinHeight - sinTop) / 2 - (iW * sCtrH) / 2  
        pozYStart = (sinWidth - sinLeft) / 2 - (iK * sCtrW) / 2  
        pozX = pozXStart: pozY = pozYStart  
          
        With Me  
            For i = 1 To iW  
                For j = 1 To iK  
                    a = a + 1  
                    Set objTB = .Controls.Add(bstrProgID:="Forms.ToggleButton.1", _  
                                              Name:=CStr(a), _  
                                              Visible:=True)  
                    With objTB  
                        .Top = pozX: .Left = pozY  
                        .Height = sCtrH: .Width = sCtrW  
                        .Tag = i & ";" & j  
                    End With  
                      
                    Set objTBButton = New clsTBEvents  
                    Set objTBButton.TBButton = objTB  
                    colTB.Add objTBButton, objTB.Name  
                      
                    pozY = pozY + sCtrW  
                Next  
                pozX = pozX + sCtrW: pozY = pozYStart  
            Next  
            .ToggleButton1.Caption = "Reset"  
        End With  
          
        tblM = TabelaMin(1, iK * iW, iM)  
        SortowanieBabelkowe tblM  
        tblMiny = tblM  
          
        ileFlag = 0: ilePol = 0  
        Set objTBButton = Nothing  
    Else  
        For Each objCtr In Me.Controls  
            If TypeName(objCtr) = "ToggleButton" And objCtr.Tag <> "Start" Then  
                Me.Controls.Remove objCtr.Name  
            End If  
        Next  
        Set colTB = Nothing  
        With Me  
            .ToggleButton1.Caption = "Start"  
            .TextBox4 = ""  
            .TextBox5 = ""  
            .Label7.Caption = ""  
            .Label6.Caption = ""  
        End With  
          
        bKoniec = False  
    End If  
End Sub  
 
Fragmentami będzie łatwiej :-))..  
 
    If Me.ToggleButton1 Then  
        '...  
        Me.ToggleButton1.Caption = "Reset"  
    Else  
        '...  
        Me.ToggleButton1.Caption = "Start"  
    End If  
 
Jednym przyciskiem będziemy realizowali dwie funkcje. ToggleButton gdy jest kliknięty to jego domyślna właściwość Value = True  
Stąd pierwszy If. I zmiana Caption na taki który określi funkcję przycisku po jego następnym kliknięciu.  
 
    Więc najpierw tworzymy planszę. Ale gdzie??. Napisałem że będzie na nią miejsce po lewej stronie UserForm'a i będzie to min 360x360  
Plansza to zestaw przylegających do siebie ToggleButton'ów. Naszym zadaniem będzie umieszczenie planszy na środku przeznaczonego  
dla niej obszaru.  
 
    Dim pozXStart As Single, pozYStart As Single  
 
    Const sCtrH As Single = 18  
    Const sCtrW As Single = 18  
      
    Const sinTop As Single = 5  
    Const sinHeight As Single = 365  
    Const sinLeft As Single = 5  
    Const sinWidth As Single = 365  
 
        With Me  
            iW = CInt(.TextBox1)  
            iK = CInt(.TextBox2)  
            iM = CInt(.TextBox3)  
        End With  
          
        pozXStart = (sinHeight - sinTop) / 2 - (iW * sCtrH) / 2  
        pozYStart = (sinWidth - sinLeft) / 2 - (iK * sCtrW) / 2  
 
A więc.. Znając wymiary pojedynczego elementu planszy: sCtrH i sCtrW oraz wymiary obszaru: sinTop, sinHeigth, sinLeft, sinWidth oraz  
ilość elementów w pionie i poziomie planszy: iW i iK można określić punkt od którego należy zacząć wstawiać elementy planszy.  
Zmienne iK i iW są zadeklarowane jako Publiczne zmienne poziomu modułu w mod. Standardowym ponieważ przydadzą się nam również  
w innych miejscach. To określamy ich wartości.  
 
    Znając punkt od którego będziemy zaczynać możemy zacząć wstawiać przyciski - elementy planszy.  
 
    Dim i As Integer, j As Integer  
    Dim objTB As MSForms.ToggleButton  
    Dim pozX As Single, pozY As Single  
    Dim objTBButton As clsTBEvents  
 
        pozX = pozXStart: pozY = pozYStart  
          
        With Me  
            For i = 1 To iW  
                For j = 1 To iK  
                    a = a + 1  
                    Set objTB = .Controls.Add(bstrProgID:="Forms.ToggleButton.1", _  
                                              Name:=CStr(a), _  
                                              Visible:=True)  
                    With objTB  
                        .Top = pozX - sCtrH: .Left = pozY + sCtrW  
                        .Height = sCtrH: .Width = sCtrW  
                        .Tag = i & ";" & j  
                    End With  
                      
                    Set objTBButton = New clsTBEvents  
                    Set objTBButton.TBButton = objTB  
                    colTB.Add objTBButton, objTB.Name  
                      
                    pozY = pozY + sCtrW  
                Next  
                pozX = pozX + sCtrW: pozY = pozYStart  
            Next  
            .ToggleButton1.Caption = "Reset"  
        End With  
 
Kontrolkom nadaję nazwę odpowiadającą numerowi kolejności ich tworzenia. Oraz do właściwości Tag trafiają "współrzędne" danego  
elementu. Nazwa posłuży nam do określenia czy w danym elemencie jest mina, a współrzędne pomogą w określeniu współrzędnych  
sąsiadów - ale o tym później.  
 
  Jednak nie wystarczy wstawić planszy trzeba również móc kontrolować zdarzenia (choćby Kliknięcia) elementów tej planszy. Nie da się  
określić ile przycisków należałoby oprogramować dlatego należy oprogramować przechwycenie zdarzeń dla całej grupy kontrolek. Których  
kontrolek? Ano właśnie tworzonych stąd fragment  
 
    Dim objTBButton As clsTBEvents  
 
i w pętli.  
 
                    Set objTBButton = New clsTBEvents  
                    Set objTBButton.TBButton = objTB  
                    colTB.Add objTBButton, objTB.Name  
 
W module class o nazwie clsTBEvents piszemy:  
 
Dim WithEvents objTB As MSForms.ToggleButton  
 
Public Property Set TBButton(tenCmdButton As MSForms.ToggleButton)  
    Set objTB = tenCmdButton  
End Property  
 
a kolekcję tworzonych kontrolek których zdarzenia będziemy przechwytywać zadeklarujemy jako Publiczną kolekcję poziomu modułu w  
mod. Standardowym.  
 
Public colTB As New Collection  
 
Mamy planszę - rozmieśćmy miny :-)  
    Odpowiada za to fragment:  
 
    Dim tblM As Variant  
 
        tblM = TabelaMin(1, iK * iW, iM)  
        SortowanieBabelkowe tblM  
        tblMiny = tblM  
 
W mod. Standardowym znajdują się Funkcja TabelaMin oraz Procedura SortowanieBabelkowe.  
 
Public Function TabelaMin(nrMin As Integer, _  
                          nrMax As Integer, _  
                          ileMin As Integer) As Variant  
                            
    Dim tbl() As Integer, i As Integer  
    Dim col As New VBA.Collection, colItem As Integer  
      
    ReDim tbl(1 To ileMin)  
    Randomize  
      
    On Error Resume Next  
    For i = 1 To ileMin  
        Do  
            colItem = Int((nrMax - nrMin + 1) * Rnd + nrMin)  
            col.Add colItem, CStr(colItem)  
            If Err.Number = 0 Then  
                Exit Do  
            Else  
                Err.Clear  
            End If  
        Loop  
        tbl(i) = colItem  
    Next  
    On Error GoTo 0  
    TabelaMin = tbl  
End Function  
 
Public Sub SortowanieBabelkowe(tabl)  
    Dim xMax As Long  
    Dim i As Long, j As Long, a As Long  
    Dim Temp  
 
    xMax = UBound(tabl, 1)  
    a = 2  
    For i = 2 To xMax  
        For j = xMax To a Step -1  
            If tabl(j - 1) > tabl(j) Then  
                Temp = tabl(j - 1)  
                tabl(j - 1) = tabl(j)  
                tabl(j) = Temp  
            End If  
        Next  
        a = a + 1  
    Next  
End Sub  
 
TabelaMin określi wartości Publicznej Tablicy poziomu mod. Zadeklarowanej w mod. Standardowym  
 
Public tblMiny() As Integer  
 
Sortuję tą tablicę bo do określenia czy dany element (jego nazwa) znajduje się w tej tablicy czy nie poprzez funkcję arkuszową .  
Application.Match (PODAJ.POZYCJĘ)   
    Co prawda typ porównania określam jako 0 więc elementy w tablicy mogą być umieszczone w dowolnej kolejności jednak na etapie  
testów łatwiej mi było sprawdzać poprawność działania funkcji.  
Więc jeżeli funkcja nie zwróci błędu trafiliśmy na minę :-)   
 
Do omówienia działania przycisku pozostaje nam (poza paroma szczegółami) oprogramowanie Resetowania Planszy:  
 
        For Each objCtr In Me.Controls  
            If TypeName(objCtr) = "ToggleButton" And objCtr.Tag <> "Start" Then  
                Me.Controls.Remove objCtr.Name  
            End If  
        Next  
 
Pozostałe elementy to czyszczenie kontrolek z opisami, zerowanie jeszcze nie omówionych publicznych zmiennych, ale o tym później.  
 
LPM na elemencie planszy  
 
Mamy więc planszę i możemy przechwycić zdarzenie kliknięcia na jej elementy. Zaczynamy więc grę... :-P  
 
Private Sub objTB_Click()  
    Dim vArg As Variant  
    Dim colItem As Integer  
    Dim objCtr As MSForms.Control  
    Dim tblS As Variant, iTbl As Integer, sMsg As String  
    Dim vMin As Variant, ileMin As Byte  
    Dim iMin As Integer  
      
    If bKoniec Then  
        If Not bEventsNotEnabled Then  
            bEventsNotEnabled = True  
            objTB.Value = Not objTB.Value  
            bEventsNotEnabled = False  
        End If  
        Exit Sub  
    End If  
      
    If Not bEventsNotEnabled Then  
        With objTB  
            If .Value Then  
                vArg = Application.Match(CInt(.Name), tblMiny, 0)  
                '---------------------trafienie na pole bez miny -----------------------  
                If TypeName(vArg) = "Error" Then  
                      
                    ilePol = ilePol + 1  
                    With UserForm1  
                        .TextBox5 = ilePol  
                        .Label6.Caption = "z: " & iK * iW - iM  
                        If ilePol = iK * iW - iM Then  
                            For iMin = 1 To UBound(tblMiny)  
                                Set objCtr = UserForm1.Controls(CStr(tblMiny(iMin)))  
                                With objCtr  
                                    .Font.Name = "Wingdings"  
                                    .Caption = Chr(77)  
                                End With  
                            Next  
                            With .Label7  
                                .Caption = "WYGRAŁEŚ" & Chr(10) & _  
                                           "Koniec Gry :-)"  
                                .ForeColor = &HFF0000  
                                bKoniec = True  
                            End With  
                        End If  
                    End With  
                      
                    '-----------ile min w sąsiedztwie----------------  
                    tblS = NazwySasiadow(objTB)  
                    For iTbl = 1 To UBound(tblS)  
                        vMin = Application.Match(CInt(tblS(iTbl)), tblMiny, 0)  
                        If TypeName(vMin) <> "Error" Then ileMin = ileMin + 1  
                    Next  
                    '-----------------Jeżeli zero to kliknij sąsiadów  
                    If ileMin = 0 Then  
                        For iTbl = 1 To UBound(tblS)  
                            vMin = Application.Match(CInt(tblS(iTbl)), tblMiny, 0)  
                            If TypeName(vMin) = "Error" Then  
                                Set objCtr = UserForm1.Controls(tblS(iTbl))  
                                With objCtr  
                                    .BackColor = &H8000000F  
                                    If Not .Value Then .Value = True  
                                    DoEvents  
                                End With  
                            End If  
                        Next  
                    Else  
                        .BackColor = &H8000000F  
                        .Font.Bold = True  
                        .Caption = ileMin  
                        .Font.Name = "Arial"  
                    End If  
                Else  
                '------------------------ mina - koniec gry --------------------------  
                    bEventsNotEnabled = True  
                    For iMin = 1 To UBound(tblMiny)  
                        Set objCtr = UserForm1.Controls(CStr(tblMiny(iMin)))  
                        With objCtr  
                            .Value = True  
                            .BackColor = &HFF 'Czerwony  
                            .Font.Name = "Wingdings"  
                            .Caption = Chr(77)  
                        End With  
                    Next  
                    bEventsNotEnabled = False  
                    With UserForm1.Label7  
                        .Caption = "MINA" & Chr(10) & _  
                                   "Koniec Gry :-("  
                        .ForeColor = &HFF  
                    End With  
                    bKoniec = True  
                End If  
                .Enabled = False  
            End If  
        End With  
    End If  
    Set objCtr = Nothing  
End Sub  
 
    Najpierw omówię znaczenie bKoniec i bEventsNotEnabled:  
Są to dwie Boolen'owski zmienne poziomu mod. Zadeklarowane w mod. Standardowym. bKoniec przyjmie wartość True gdy trafimy na minę  
lub wygramy. Chodzi o uniemożliwienie klikania na elementy planszy po zakończeniu gry. Gdy nastąpił już koniec kliknięta kontrolka wraca  
do poprzedniego stanu: objTB.Value = Not objTB.Value jednak taki manewr wywołałby kolejne zdarzenie. Kontrolę nad niechcianym  
wystąpieniem zdarzeń daje nam zastosowanie zmiennej bEventsNotEnabled. Jest ona potrzebna bo stosując mod. Class nie wystarczy  
samo żonglowanie Application.EnableEvents  
 
    If bKoniec Then  
        If Not bEventsNotEnabled Then  
            bEventsNotEnabled = True  
            objTB.Value = Not objTB.Value  
            bEventsNotEnabled = False  
        End If  
        Exit Sub  
    End If  
 
elektem zastosowanie zmiennej bEventsNotEnabled jest fakt że wszystko pomiędzy liniami  
    bEventsNotEnabled = True  
    bEventsNotEnabled = False  
zostanie jakby wyłączone z obsługi zdarzenia. Jakby - ponieważ zdarzenie i reakcja na niego będą miały miejsce ale odpowiednim  
warunkiem na początku procedury nic się nie wykona.  
 
        With objTB  
            If .Value Then  
                vArg = Application.Match(CInt(.Name), tblMiny, 0)  
                '---------------------trafienie na pole bez miny -----------------------  
                If TypeName(vArg) = "Error" Then  
                      
                    ilePol = ilePol + 1  
                    With UserForm1  
                        .TextBox5 = ilePol  
                        .Label6.Caption = "z: " & iK * iW - iM  
                        If ilePol = iK * iW - iM Then  
                            For iMin = 1 To UBound(tblMiny)  
                                Set objCtr = UserForm1.Controls(CStr(tblMiny(iMin)))  
                                With objCtr  
                                    .Font.Name = "Wingdings"  
                                    .Caption = Chr(77)  
                                End With  
                            Next  
                            With .Label7  
                                .Caption = "WYGRAŁEŚ" & Chr(10) & _  
                                           "Koniec Gry :-)"  
                                .ForeColor = &HFF0000  
                                bKoniec = True  
                            End With  
                        End If  
                    End With  
 
Sprawdzamy czy .Name klikniętej kontrolki znajduje się w tblMiny. Nazwę tą trzeba skonwertować do liczby gdyż w tblMiny mamy liczby.  
Jeżeli nie trafimy w minę:  
 - ilePol to zmienna publ. Poziomu mod. Zadeklarowana w mod. Standardowym przechowująca ilość odkrytych pól. Wartość ta jest  
   zwracana do TextBox5 będącego częścią informacyjną Formularza.  
   Jeżeli ilePol = iK * iW - iM tzn: ilość kontrolek - ilość min tj. ilość kontrolek bez min to Wygraliśmy :-)))  
   Pokazujemy wtedy gdzie były miny:  
                            For iMin = 1 To UBound(tblMiny)  
                                Set objCtr = UserForm1.Controls(CStr(tblMiny(iMin)))  
                                With objCtr  
                                    .Font.Name = "Wingdings"  
                                    .Caption = Chr(77)  
                                End With  
                            Next  
   i w odpowiednie miejsce zwracamy informację o zwycięstwie. Następnie bKoniec = True i po zabawie.  
 
Jeżeli jednak w ilePol nie uzbierało się iK*iW - iM to ..  
 
                    '-----------ile min w sąsiedztwie----------------  
                    tblS = NazwySasiadow(objTB)  
                    For iTbl = 1 To UBound(tblS)  
                        vMin = Application.Match(CInt(tblS(iTbl)), tblMiny, 0)  
                        If TypeName(vMin) <> "Error" Then ileMin = ileMin + 1  
                    Next  
i  
 
Function NazwySasiadow(objCtr As MSForms.ToggleButton) As Variant  
    Dim nr As Integer  
    Dim iKol As Integer, iWie As Integer  
    Dim i As Integer, j As Integer  
    Dim tblWyniki() As String, iTbl As Integer  
      
    With objCtr  
        nr = CInt(.Name)  
        iWie = CInt(Split(.Tag, ";")(0))  
        iKol = CInt(Split(.Tag, ";")(1))  
    End With  
      
    For i = iWie - 1 To iWie + 1  
        For j = iKol - 1 To iKol + 1  
            If Not (i = iWie And j = iKol) Then  
                If i > 0 And i < iW + 1 Then  
                    If j > 0 And j < iK + 1 Then  
                        iTbl = iTbl + 1  
                        ReDim Preserve tblWyniki(iTbl)  
                        tblWyniki(iTbl) = j + iK * (i - 1)  
                    End If  
                End If  
            End If  
        Next  
    Next  
    NazwySasiadow = tblWyniki  
End Function  
 
Funkcja NazwySasiadow przegląda przyciski będące sąsiadami klikniętego przycisku i zwraca ich nazwy.  
    Przekazywana jest do niej w arg. Kliknięta kontrolka. Znamy więc jej nazwę - kolejny numer utworzenia, i jej współrzędne - wł. Tag.  
Poprzez określenie współrzędnych istniejących sąsiadów określane są ich nazwy i zwracane w tablicy jako wynik funkcji.  
    Następnie, już w procedurze sprawdzani są w pętli sąsiedzi w poszukiwaniu tych których nazwa znajduje się w tblMiny. Ich liczba  
jest zwracana w zmiennej ileMin  
 
                    If ileMin = 0 Then  
                        For iTbl = 1 To UBound(tblS)  
                            vMin = Application.Match(CInt(tblS(iTbl)), tblMiny, 0)  
                            If TypeName(vMin) = "Error" Then  
                                Set objCtr = UserForm1.Controls(tblS(iTbl))  
                                With objCtr  
                                    .BackColor = &H8000000F  
                                    If Not .Value Then .Value = True  
                                    DoEvents  
                                End With  
                            End If  
                        Next  
 
Jeżeli ileMin = 0 to trzeba określić czy sąsiedzi naszej komórki mają minę. I jak nie to ich kliknąć :-) zauważmy że nie wyłączyłem   
zdarzeń. Kliknięcie wywoła procedurę od nowa, określi sąsiadów nowo-klikniętej kontrolki i przeprowadzi na niej te same testy i tak w  
kółko dopóki ilość sąsiadów w których znajduje się mina badanych kontrolek będzie > 0 lub ilość odkrytych pól = iW*iK - iM i wygramy.  
    Tu tak naprawdę jest już po zabawie. Napisanie tej gry staje się proste i logiczne.  
Jeżeli ileMin > 0:  
 
                    Else  
                        .BackColor = &H8000000F  
                        .Font.Bold = True  
                        .Caption = ileMin  
                        .Font.Name = "Arial"  
                    End If  
 
Pozostaje nam jeszcze niefart - trafienie na minę:  
 
                    bEventsNotEnabled = True  
                    For iMin = 1 To UBound(tblMiny)  
                        Set objCtr = UserForm1.Controls(CStr(tblMiny(iMin)))  
                        With objCtr  
                            .Value = True  
                            .BackColor = &HFF 'Czerwony  
                            .Font.Name = "Wingdings"  
                            .Caption = Chr(77)  
                        End With  
                    Next  
                    bEventsNotEnabled = False  
                    With UserForm1.Label7  
                        .Caption = "MINA" & Chr(10) & _  
                                   "Koniec Gry :-("  
                        .ForeColor = &HFF  
                    End With  
                    bKoniec = True  
 
Wyłączamy zdarzenia i odkrywamy kontrolki których nazwy znajdują się w tblMiny. Określamy ich wypełnienie na czerwone, zwracamy  
info o przegranej i bKoniec = True  
 
Ps: Na bKoniec = False przełączymy po resecie.  
 
Jeszcze flaga i ilość flag a więc  
PPM na elemencie Planszy  
 
Private Sub objTB_MouseDown(ByVal Button As Integer, ByVal Shift As Integer, ByVal X As Single, ByVal Y As Single)  
    If Button = 2 Then  
        With objTB  
            If Len(.Caption) = 0 Then  
                .Font.Name = "Wingdings"  
                .Caption = Chr(79)  
                ileFlag = ileFlag + 1  
                UserForm1.TextBox4.Text = ileFlag  
            Else  
                .Font.Name = "Arial"  
                .Caption = ""  
                UserForm1.TextBox4.Text = IIf(ileFlag > 0, ileFlag - 1, 0)  
            End If  
        End With  
    End If  
End Sub  
 
co tu tłumaczyć :-))  
 
siema. Pierwsza gra za nami :-))  
Wiem że wszystkiego w najdrobniejszych szczegółach nie opisałem ale myslę że reszty idzie się domyślić.   
To wersja nr 1.0 ;) niewylkuczone poprawki.