Gra w kropki

Gra w kropki jest kolejną znaną ze szkoły grą, którą sobie stworzymy. W grze chodzi o to, aby okrążyć kropki przeciwnika. Sam grałem w liceum w kropki dość często, głównie na religii :P. Mam duży sentyment do tej gry więc kiedy nauczyłem się programować, bardzo chciałem taką grę zrobić. Po kilku nieudanych próbach trochę się poddałem, ale powróciłem do projektu i dokończyłem go. Forma, którą zademonstruje tutaj w tutorialu, jest dosyć prosta:

Kropki1

 

 

Rodzaj elementu Nazwa elementu Ustawienia
Form Form1 Name: Form1
Text: Kropko mania
Size: 840; 663
Panel Panel_glowny Name: Panel_glowny
Size: 800; 600
Location: 12;12
BackColor: White
Anchor: Top, Bottom, Left, Right

 

 

Istnieje także program do pobrania mojego autorstwa, w którym można pograć ze znajomym poprzez sieć LAN, jak ktoś potrafi przekierować porty to również przez internet, przed monitorem z kolegą lub samemu z komputerem:

iconaDoKropek

 

 

Do pobrania tutaj: KropkoMania 1.4

 

 

 

W tym tutorialu gra zacznie się w momencie uruchomienia programu, nie ma co kombinować i budować niepotrzebnych przycisków i elementów upiększających, które tylko przysłonią i zamglą główny silnik gry. Nasza gra będzie wyglądać tak jak na gifie poniżej:

Każdy, kto zrozumie, na czym polega sposób okrążania kropek, będzie umiał dodać sobie dodatkowe elementy. Tworzymy Form_Load:

Public Class Form1
    'wielkość planszy do gry
    Dim wysokosc As Integer = 15
    Dim szerokosc As Integer = 20
    Dim listaLokalizacji As New List(Of List(Of Panel)) 'lista wszystkich paneli na planszy


    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

        For i As Integer = -2 To szerokosc +1
            Dim listapaneli As New List(Of Panel)
            For j As Integer = -2 To wysokosc +1
                Dim panelPodstawowy As New Panel
                With panelPodstawowy
                    .Location = New Point(i * 40 + 30, j * 40 + 30)
                    .Size = New Size(20, 20)
                    .BackColor = Color.Transparent
                    .Name = "panL_" + i.ToString + "^" + j.ToString + "^"
                    .Cursor = Cursors.Hand
                    'AddHandler .Click, AddressOf pan_Click

                    'Obrzeże kartki, wyjaśnie na blogu
                     If i = -2 Or i = -1 Or j = -1 Or j = -2 Or i = szerokosc Or j = wysokosc Or i = szerokosc _
+ 1 Or j = wysokosc + 1 Then
                        .Enabled = False
                    End If
                End With
                Panel_glowny.Controls.Add(panelPodstawowy) ' dodaje element do panelu
                listapaneli.Add(panelPodstawowy)
            Next
            'zmienna przechowuje wszystkie panele kartki
            listaLokalizacji.Add(listapaneli)
        Next

        'Generuje kratkę kartki
        Dim bit As Bitmap = New Bitmap(Panel_glowny.Width, Panel_glowny.Height)
        Dim g As Graphics = Graphics.FromImage(bit)

        Dim myPen As Pen = New Pen(Color.FromArgb(191, 218, 229), 1)
        For i As Integer = 40 To Panel_glowny.Height Step 40
            g.DrawLine(myPen, 0, i, Panel_glowny.Width, i)
        Next
        For i As Integer = 40 To Panel_glowny.Width Step 40
            g.DrawLine(myPen, i, 0, i, Panel_glowny.Height)
        Next

        Panel_glowny.BackgroundImage = bit

    End Sub
End Class

Po uruchomieniu programu naszym oczom powinna pokazać się, gotowa do kropkowania strona, można się pokusić o taką jej zmianę, aby bardziej przypominała stronę z zeszytu. Ważnym elementem, na który powinniśmy zwrócić uwagę, jest wystawanie naszych paneli poza obszar kartki. Ponieważ podczas działania programu elementy będą rozpatrywane w pewien logiczny sposób, proces ten będzie wymagał sprawdzania elementów powyżej, poniżej, z lewej i z prawej strony kropki dodanie dodatkowych paneli, do których użytkownik nie będzie miał dostępu na początku, będzie wygodniejsze niż wprowadzanie ograniczeń. Jeśli pokolorujemy te obszary, będą one wyglądały tak jak na zdjęciu:

graWkropki1

Obszary te będą traktowane jako obszary puste, a ich zablokowanie upewni nas, że takie pozostaną. Jeśli czytaliście tutorial o grze w piłkarzyki, dodanie kropek nie powinno dla was stanowić problemu. Odblokowujemy:

AddHandler .Click, AddressOf pan_Click

Dodajemy kod:

    'aktualny gracz
    Dim gracz As Boolean = True
    'listy kropek
    Dim listaKropekGracz1 As New List(Of Panel)
    Dim listaKropekGracz2 As New List(Of Panel)
    Dim bit As Bitmap
    Dim g As Graphics
    'kolory
    Dim zielony As New System.Drawing.SolidBrush(System.Drawing.Color.Green)
    Dim czerwony As New System.Drawing.SolidBrush(Color.Red)

    Public Sub pan_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)

        If gracz Then 'zielony
            bit = New Bitmap(20, 20)
            g = Graphics.FromImage(bit)
            'dodaje zajęty panel do listy
            listaKropekGracz1.Add(DirectCast(sender, Panel))
            g.FillEllipse(zielony, New Rectangle(5, 5, 10, 10))
            DirectCast(sender, Panel).BackgroundImage = bit
            DirectCast(sender, Panel).Enabled = False
            '''''''''testOkrazenia()
        Else ' czerwony
            bit = New Bitmap(20, 20)
            g = Graphics.FromImage(bit)
            'dodaje zajęty panel do listy
            listaKropekGracz2.Add(DirectCast(sender, Panel))
            g.FillEllipse(czerwony, New Rectangle(5, 5, 10, 10))
            DirectCast(sender, Panel).BackgroundImage = bit
            DirectCast(sender, Panel).Enabled = False
            '''''''''testOkrazenia()
        End If

    End Sub

Są już kropki. Jeden kolor, bo gracz nie zmienia statusu na false, ale będzie to robił w innej pętli. Ponieważ wymagają tego zasady gry. Kiedy gracz okrąży przeciwnika, może położyć dodatkową kropkę.

graWkropki2

Jeśli chodzi o łatwe rzeczy, to właśnie się skończyły. Teraz musicie ogarnąć, co mam na myśli, tłumacząc sposób działania kilku elementów. Najtrudniejszym elementem gry jest stwierdzenie, czy kropki są okrążone. Kiedy kropka jest jedna, to sytuacja jest oczywista. Należy sprawdzić na naszej liście czy ze wszystkich czterech stron nasza kropka jest otoczona przez kropki przeciwnika. Niestety jest to jedna z wielu sytuacji, które musimy rozpatrywać. Będę starał się tłumaczyć co i jak, jeśli ktoś nie zrozumie, to  może napisać mi maila lub zostawi komentarz. Odblokowujemy:

testOkrazenia()

Kod tego elementu razem z pierwszą funkcją wygląda następująco:

  Private Sub testOkrazenia()
        Dim listabrzegowa As New List(Of Panel)
        'Dodaje elementy sąsiadujące z kropkami do listy
        If Not listaKropekGracz1.Count = 0 Then
            listabrzegowa.AddRange(brzegi(listaKropekGracz1))
        End If
        If Not listaKropekGracz2.Count = 0 Then
            listabrzegowa.AddRange(brzegi(listaKropekGracz2))
        End If

    End Sub

    'Funkcja zwraca elementy sąsiadujące z kropkami
    Private Function brzegi(ByRef listagracza As List(Of Panel)) As List(Of Panel)
        Dim listanabrzezna As New List(Of Panel) 'przechowuje elementy sąsiadujące
        For k As Integer = 0 To listagracza.Count - 1

            Dim pozycjax As Integer = 0
            Dim pozycjay As Integer = 0
            'pobiera aktualną pozycję panelu
            For i As Integer = 0 To listaLokalizacji.Count - 1
                For j As Integer = 0 To listaLokalizacji(i).Count - 1
                    If listaLokalizacji(i)(j).Name = listagracza(k).Name Then
                        pozycjax = i
                        pozycjay = j
                    End If
                Next
            Next
            'sprawdza czy z lewej, prawej, góry i dołu znajdują się jakieś puste elementy
            If Not listanabrzezna.Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) And _
Not listaKropekGracz1.Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) And _
Not listaKropekGracz2.Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) Then
                listanabrzezna.Add(listaLokalizacji(pozycjax - 1)(pozycjay))
            End If
            If Not listanabrzezna.Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) And _
Not listaKropekGracz1.Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) And _
Not listaKropekGracz2.Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) Then
                listanabrzezna.Add(listaLokalizacji(pozycjax + 1)(pozycjay))
            End If
            If Not listanabrzezna.Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) And _
 Not listaKropekGracz1.Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) And _
Not listaKropekGracz2.Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) Then
                listanabrzezna.Add(listaLokalizacji(pozycjax)(pozycjay + 1))
            End If
            If Not listanabrzezna.Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) And _
Not listaKropekGracz1.Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) And _
Not listaKropekGracz2.Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) Then
                listanabrzezna.Add(listaLokalizacji(pozycjax)(pozycjay - 1))
            End If
        Next
        Return listanabrzezna
    End Function

Metody zawarte w funkcji powyżej zwracają nam listę elementów sąsiadujących z kropkami.

graWkropki3 elementyGraniczące

 

 

 

 

 

 

 

 

 

Na zdjęciach widzimy pokolorowane elementy sąsiadujące. Kolejnym etapem jest stworzenie pewnej szczególnej listy elementów. Ja nazywam tę listę „listą wolności”. Każde zderzenie się elementu lub grupy podczas sprawdzania okrążenia z tą listą będzie oznaczało, że kropka/ki nie są okrążone.

    Private Sub testOkrazenia()
        Dim listabrzegowa As New List(Of Panel)
        'Dodaje elementy sąsiadujące z kropkami do listy
        If Not listaKropekGracz1.Count = 0 Then
            listabrzegowa.AddRange(brzegi(listaKropekGracz1))
        End If
        If Not listaKropekGracz2.Count = 0 Then
            listabrzegowa.AddRange(brzegi(listaKropekGracz2))
        End If


        Dim listaWolnosci As New List(Of List(Of Panel))
        listaWolnosci = freedomPoints(listabrzegowa)

    End Sub

    'Punkty wolności
    Private Function freedomPoints(ByRef Sasiadujace As List(Of Panel)) As List(Of List(Of Panel))
        Dim listapaneli As New List(Of List(Of Panel))

        Dim dlugoscListy As Integer = listaLokalizacji(0).Count
        Dim wielkoscListy As Integer = listaLokalizacji.Count
        'dodawanie elementów z dołu
        For i As Integer = wielkoscListy - 1 To 0 Step -1
            Dim lista As New List(Of Panel)
            For j As Integer = dlugoscListy - 1 To 0 Step -1
                If Not Sasiadujace.Contains(listaLokalizacji(i)(j)) Then
                    lista.Add(listaLokalizacji(i)(j))
                Else
                    Exit For
                End If

            Next
            listapaneli.Add(lista)
        Next
        'dodawanie elementów z góry
        For i As Integer = 0 To wielkoscListy - 1
            Dim lista As New List(Of Panel)
            For j As Integer = 0 To dlugoscListy - 1
                If Not Sasiadujace.Contains(listaLokalizacji(i)(j)) Then
                    lista.Add(listaLokalizacji(i)(j))
                Else
                    Exit For
                End If

            Next
            listapaneli.Add(lista)
        Next
        'dodawanie elementów z prawej strony
        For i As Integer = dlugoscListy - 1 To 0 Step -1
            Dim lista As New List(Of Panel)
            For j As Integer = wielkoscListy - 1 To 0 Step -1
                If Not Sasiadujace.Contains(listaLokalizacji(j)(i)) Then
                    lista.Add(listaLokalizacji(j)(i))
                Else
                    Exit For
                End If
            Next
            listapaneli.Add(lista)
            If i = wielkoscListy Then
                Exit For
            End If
        Next
        'dodawanie elementów z lewej strony
        For i As Integer = 0 To dlugoscListy - 1
            Dim lista As New List(Of Panel)
            For j As Integer = 0 To wielkoscListy - 1
                If Not Sasiadujace.Contains(listaLokalizacji(j)(i)) Then
                    lista.Add(listaLokalizacji(j)(i))
                Else
                    Exit For
                End If
            Next
            listapaneli.Add(lista)
            If i = wielkoscListy Then
                Exit For
            End If
        Next
        Return listapaneli
    End Function

Funkcja ta zwraca nam listę która zawiera elementy:
graWkropki4

 

Jak widać na obrazku, do naszej listy niedodawane są elementy graniczące z kropką, ponieważ są one przechowywane w innej liście. Jak funkcja ta działa, gdy mamy więcej elementów? Otóż tak jak na obrazku poniżej:

elementyStrefoweipuste

Fioletowe i niebieskie elementy to efekt funkcji „freedomPoints”, a czerwone to efekt funkcji „brzegi”. Spójrzcie na elementy w środku, okrążone przez zielone kropki. Nie mają żadnego koloru. Są one bardzo ważne, ponieważ będą naszą drogą do wolności lub okrążenia. Zaczniemy teraz bardzo ważny rozdział, w którym pogrupujemy sobie nasze kropki. Ważnym elementem będzie tutaj odgrywał gracz, musimy wiedzieć który gracz właśnie postawił kropkę. Taką wiedzę daje nam zmienna „gracz”. W momencie, gdy stawiana jest kropka zielona, nie rozpatrujemy, tak jak by nam się mogło zdawać kropek zielonych a kropki czerwone. Ponieważ wszystkie kropki gracza czerwonego grupujemy i każdą grupę po kolei rozpatrujemy czy dąży do naszej „ListyWolności”, jeśli nie, oznacza to, że jest okrążona.
Wstępne grupowanie jest dosyć proste. Tworzymy grupy elementów sąsiadujących, dodajemy je do listy, a następnie te listy, które zawierają te same elementy, łączymy ze sobą:

 

graWkropki5

Zobaczmy jak wygląda kod metody:

   Private Sub testOkrazenia()
        Dim listabrzegowa As New List(Of Panel)
        'Dodaje elementy sąsiadujące z kropkami do listy
        If Not listaKropekGracz1.Count = 0 Then
            listabrzegowa.AddRange(brzegi(listaKropekGracz1))
        End If
        If Not listaKropekGracz2.Count = 0 Then
            listabrzegowa.AddRange(brzegi(listaKropekGracz2))
        End If


        Dim listaWolnosci As New List(Of List(Of Panel))
        listaWolnosci = freedomPoints(listabrzegowa)

        Dim listagrup As New List(Of List(Of Panel))

        If gracz Then 'zielony
            listagrup = grupuj(listaKropekGracz2)
        Else 'czerwony
            listagrup = grupuj(listaKropekGracz1)
        End If

    End Sub

    'funkcja tworzy wstępne grupy kropek
    Private Function grupuj(ByRef listagracza As List(Of Panel)) As List(Of List(Of Panel))
        Dim grupy As New List(Of List(Of Panel))
        'wylicza wszystkie kropki przeciwnika
        For k As Integer = 0 To listagracza.Count - 1
            Dim kontynuacja As Boolean = True 'blokada, nie dodaje kropek jeśli już się znajdują w jakiejś grupie
            For i As Integer = 0 To grupy.Count - 1
                If grupy(i).Contains(listagracza(k)) Then
                    kontynuacja = False
                    Exit For
                End If
            Next
            If kontynuacja = True Then
                Dim listaPunktowa As New List(Of Panel)
                listaPunktowa.Add(listagracza(k))
                'pobiera pozycję kropki
                Dim pozycjax As Integer = 0
                Dim pozycjay As Integer = 0
                For i As Integer = 0 To listaLokalizacji.Count - 1
                    For j As Integer = 0 To listaLokalizacji(i).Count - 1
                        If listaLokalizacji(i)(j).Name = listagracza(k).Name Then
                            pozycjax = i
                            pozycjay = j
                        End If
                    Next
                Next
                'łączy sąsiedne punkty w grupy
                If Not listaPunktowa.Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) And _
listagracza.Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) Then
                    listaPunktowa.Add(listaLokalizacji(pozycjax - 1)(pozycjay))
                End If
                If Not listaPunktowa.Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) And _
listagracza.Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) Then
                    listaPunktowa.Add(listaLokalizacji(pozycjax + 1)(pozycjay))
                End If
                If Not listaPunktowa.Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) And _
listagracza.Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) Then
                    listaPunktowa.Add(listaLokalizacji(pozycjax)(pozycjay + 1))
                End If
                If Not listaPunktowa.Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) And _
listagracza.Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) Then
                    listaPunktowa.Add(listaLokalizacji(pozycjax)(pozycjay - 1))
                End If
                'dodaje do listy nasze punkty
                grupy.Add(listaPunktowa)
            End If
        Next

        For i As Integer = 0 To grupy.Count - 1
            For j As Integer = 0 To grupy(i).Count - 1
                Dim panelzgrupa As Panel = grupy(i)(j)
                For r As Integer = 0 To grupy.Count - 1
                    If Not r = i And grupy(r).Contains(panelzgrupa) Then
                        'łączy listy
                        grupy(i).AddRange(grupy(r))
                        grupy(r).Clear()
                    End If
                Next
            Next
        Next
        'usuwa puste listy
        For i As Integer = grupy.Count - 1 To 0 Step -1
            If grupy(i).Count = 0 Then
                grupy.RemoveAt(i)
            End If
        Next
        Return grupy
    End Function

Najprościej pokazuje to przykład czterech kropek:

graWkropki6

W takich listach nie musimy chwilowo przejmować się powtarzającymi się elementami. Taka segregacja, jak dodamy kolory, wygląda to następująco:

grupowanieKropek

Jak widzimy, grupa B nie zalicza chwilowo pustych pól do swojej grupy, dlatego też nie wiemy, czy nasza grupa B jest na pewno okrążona, czy też nie. Ostatni etap ma na celu dodanie pustych lub brzegowych pól do naszych grup i usunięcie z listy tych grup, które łączą się z naszą listą wolności.

    Private Sub testOkrazenia()
        Dim listabrzegowa As New List(Of Panel)
        'Dodaje elementy sąsiadujące z kropkami do listy
        If Not listaKropekGracz1.Count = 0 Then
            listabrzegowa.AddRange(brzegi(listaKropekGracz1))
        End If
        If Not listaKropekGracz2.Count = 0 Then
            listabrzegowa.AddRange(brzegi(listaKropekGracz2))
        End If


        Dim listaWolnosci As New List(Of List(Of Panel))
        listaWolnosci = freedomPoints(listabrzegowa)

        Dim listagrup As New List(Of List(Of Panel))

        If gracz Then 'zielony
            listagrup = grupuj(listaKropekGracz2)
            listagrup = Edycjagrup(listaKropekGracz1, listagrup, listabrzegowa, listaWolnosci)
        Else 'czerwony
            listagrup = grupuj(listaKropekGracz1)
            listagrup = Edycjagrup(listaKropekGracz2, listagrup, listabrzegowa, listaWolnosci)
        End If

    End Sub

    Private Function Edycjagrup( ByRef listaprzeciwnika As List(Of Panel), ByRef grupy As List(Of List(Of Panel))_
, ByRef listaBrzegowa As List(Of Panel), ByRef Listastrefowa As List(Of List(Of Panel))) As List(Of List(Of Panel))
        Dim listanabrzezna As New List(Of Panel)
        'pętla sprawdza każdy element na piechotę i dodaje elementy do grup
        Do
            Dim dzialajpetlo As Boolean = False
            For k As Integer = grupy.Count - 1 To 0 Step -1
                For l As Integer = 0 To grupy(k).Count - 1
                    Dim pozycjax As Integer = 0
                    Dim pozycjay As Integer = 0
                    'pobiera aktualną pozycję naszego panelu
                    For i As Integer = 0 To listaLokalizacji.Count - 1
                        For j As Integer = 0 To listaLokalizacji(i).Count - 1
                            If listaLokalizacji(i)(j).Name = grupy(k)(l).Name Then
                                pozycjax = i
                                pozycjay = j
                            End If
                        Next
                    Next
                    Dim kontynuuj As Boolean = True
                    For i As Integer = 0 To Listastrefowa.Count - 1
                        'Element grupy dotkną elementu listy wolności, co świadczy o tym, że nie jest okrążony
                        If Listastrefowa(i).Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) Or _
Listastrefowa(i).Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) Or _
Listastrefowa(i).Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) Or _
Listastrefowa(i).Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) Then
                            kontynuuj = False
                            'usuwa listę z grupy
                            grupy.RemoveAt(k)
                            Exit For
                        End If
                    Next

                    If kontynuuj = True Then
                        'dodaje listy brzegowe 
                        If listaBrzegowa.Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) And Not _
grupy(k).Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) Then
                            grupy(k).Add(listaLokalizacji(pozycjax - 1)(pozycjay))
                            dzialajpetlo = True
                            'dodaje własne elementy i nie dodaje elementów przeciwnika
                        ElseIf  Not listaprzeciwnika.Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) And _
Not grupy(k).Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) Then
                            grupy(k).Add(listaLokalizacji(pozycjax - 1)(pozycjay))
                            dzialajpetlo = True
                        End If

                        If listaBrzegowa.Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) And Not _
grupy(k).Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) Then
                            grupy(k).Add(listaLokalizacji(pozycjax + 1)(pozycjay))
                            dzialajpetlo = True
                        ElseIf  Not listaprzeciwnika.Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) And _
Not grupy(k).Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) Then
                            grupy(k).Add(listaLokalizacji(pozycjax + 1)(pozycjay))
                            dzialajpetlo = True
                        End If

                        If listaBrzegowa.Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) And Not _
grupy(k).Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) Then
                            grupy(k).Add(listaLokalizacji(pozycjax)(pozycjay + 1))
                            dzialajpetlo = True
                        ElseIf  Not listaprzeciwnika.Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) And Not _
grupy(k).Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) Then
                            grupy(k).Add(listaLokalizacji(pozycjax)(pozycjay + 1))
                            dzialajpetlo = True
                        End If

                        If listaBrzegowa.Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) And Not _
grupy(k).Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) Then
                            grupy(k).Add(listaLokalizacji(pozycjax)(pozycjay - 1))
                            dzialajpetlo = True
                        ElseIf  Not listaprzeciwnika.Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) And Not _
grupy(k).Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) Then
                            grupy(k).Add(listaLokalizacji(pozycjax)(pozycjay - 1))
                            dzialajpetlo = True
                        End If
                    Else
                        Exit For
                    End If
                Next
            Next
            'pętla działa dopóki wszystkie elementy nie będą sprawdzone lub nie będzie już elementów w grupie
            If grupy.Count = 0 Then
                Exit Do
            ElseIf dzialajpetlo = False Then
                Exit Do
            End If
        Loop
        Return grupy
    End Function

Ta funkcja pozwoli nam na wyeliminowanie grup otwartych a zachowanie grup zamkniętych, lub opróżnienie grup jeśli wszystkie są otwarte.

okrązenie

Kiedy wiemy która grupa jest okrążona, należy ją okrążyć i wyeliminować z gry, aby przeciwnik nie mógł już ich użyć. Tę ostatnią rzecz możemy bardzo łatwo osiągnąć poprzez dodanie okrążonych elementów do „listaKropekGracz1” lub „listaKropekGracz2” wtedy dla jednego gracza kropki będą wyeliminowane a dla drugiego i tak są bezużyteczne, skoro są już okrążone. Na podstawie tych list możemy również później stwierdzić, który z graczy wygrał, jeśli będziemy mówić o wygranej w kontekście zajętego terenu. Przejdźmy do elementu rysowania linii, widząc obrazek powyżej, łatwo domyślić się jak to zrobimy. Sprawdzimy każdy okrążony element czy jest obok niego kropka przeciwnika i stworzymy sobie listę tych kropek. Następnie z listy takiej usuniemy powtarzające się elementy tak, aby zostały pojedyncze, sprawdzimy jakie elementy z nimi graniczą i stworzymy listę Tupli, która będzie przechowywać współrzędne linii.

    Dim listazlapaneGracz1 As New List(Of Panel)
    Dim listazlapaneGracz2 As New List(Of Panel)

    Private Sub testOkrazenia()
        Dim listabrzegowa As New List(Of Panel)
        'Dodaje elementy sąsiadujące z kropkami do listy
        If Not listaKropekGracz1.Count = 0 Then
            listabrzegowa.AddRange(brzegi(listaKropekGracz1))
        End If
        If Not listaKropekGracz2.Count = 0 Then
            listabrzegowa.AddRange(brzegi(listaKropekGracz2))
        End If


        Dim listaWolnosci As New List(Of List(Of Panel))
        listaWolnosci = freedomPoints(listabrzegowa)

        Dim listagrup As New List(Of List(Of Panel))

        If gracz Then 'zielony
            listagrup = grupuj(listaKropekGracz2)
            listagrup = Edycjagrup(listaKropekGracz1, listagrup, listabrzegowa, listaWolnosci)
            'listuje wszystkie elementy w grupach które pozostały
            For i As Integer = 0 To listagrup.Count - 1
                'rysuje linie i tworzy listę tupli
                rysujLinie(listagrup(i), listaKropekGracz1, listazlapaneGracz1)
                For j As Integer = 0 To listagrup(i).Count - 1
                    'elementy mogą się powtarzać, więc pętla sprawdza czy przypadkiem nie znajduą się już na liście
                    If Not listazlapaneGracz1.Contains(listagrup(i)(j)) Then
                        listazlapaneGracz1.Add(listagrup(i)(j)) 'dodaje element
                        listagrup(i)(j).Enabled = False
                        'warunek usuwa element z listy przeciwnika aby nie mógł go już używać
                        If Not listaKropekGracz2.IndexOf(listagrup(i)(j)) = -1 Then
                            listaKropekGracz2.RemoveAt(listaKropekGracz2.IndexOf(listagrup(i)(j)))
                            listaKropekGracz1.Add(listagrup(i)(j)) 'dodaje do listy aktualnego gracza
                        End If
                    End If
                Next
            Next
            'zmienia gracza jeśli nic nie zostało okrążone
            If Not listagrup.Count > 0 Then
                gracz = False
            End If
        Else 'czerwony
            listagrup = grupuj(listaKropekGracz1)
            listagrup = Edycjagrup(listaKropekGracz2, listagrup, listabrzegowa, listaWolnosci)
            'listuje wszystkie elementy w grupach które pozostały
            For i As Integer = 0 To listagrup.Count - 1
                'rysuje linie i tworzy listę tupli
                rysujLinie(listagrup(i), listaKropekGracz2, listazlapaneGracz2)
                For j As Integer = 0 To listagrup(i).Count - 1
                    'elementy mogą się powtarzać, więc pętla sprawdza czy przypadkiem nie znajduą się już na liście
                    If Not listazlapaneGracz2.Contains(listagrup(i)(j)) Then
                        listazlapaneGracz2.Add(listagrup(i)(j)) 'dodaje element
                        listagrup(i)(j).Enabled = False
                        'warunek usuwa element z listy przeciwnika aby nie mógł go już używać
                        If Not listaKropekGracz1.IndexOf(listagrup(i)(j)) = -1 Then
                            listaKropekGracz1.RemoveAt(listaKropekGracz1.IndexOf(listagrup(i)(j))) 'usuwa
                            listaKropekGracz2.Add(listagrup(i)(j)) 'dodaje do listy aktualnego gracza
                        End If
                    End If
                Next
            Next
            'zmienia gracza jeśli nic nie zostało okrążone
            If Not listagrup.Count > 0 Then
                gracz = True
            End If
        End If
    End Sub

Tak zmodyfikowany test okrążenia sprawdzi, co trzeba, dodaj go do swojego kodu. Teraz dodamy sobie ostatni element „rysujLinie”, która okrąży nasze punkty. wygląda ona tak:

    Dim listaLiniwszystkich As New List(Of Tuple(Of Panel, Panel))
    Private Sub rysujLinie(ByRef pane As List(Of Panel), ByRef listagracza As List(Of Panel), ByRef listazlapanych As List(Of Panel))

        Dim d As Graphics
        d = Panel_glowny.CreateGraphics()

        Dim listaUporzadkowanychpanelow As New List(Of Panel)

        'tworzy listę wszystkich paneli grupy bez powtórzeń
        For i As Integer = 0 To pane.Count - 1
            If Not listaUporzadkowanychpanelow.Contains(pane(i)) Then
                listaUporzadkowanychpanelow.Add(pane(i))
            End If
        Next

        Dim listaliniowych As New List(Of Panel) 'lista sąsiadujących paneli
        For k As Integer = 0 To listaUporzadkowanychpanelow.Count - 1

            Dim pozycjax As Integer = 0
            Dim pozycjay As Integer = 0
            For i As Integer = 0 To listaLokalizacji.Count - 1
                For j As Integer = 0 To listaLokalizacji(i).Count - 1
                    If listaLokalizacji(i)(j).Name = listaUporzadkowanychpanelow(k).Name Then
                        pozycjax = i
                        pozycjay = j
                    End If
                Next
            Next
            If listagracza.Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) Then
                listaliniowych.Add(listaLokalizacji(pozycjax - 1)(pozycjay))
            End If
            If listagracza.Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) Then
                listaliniowych.Add(listaLokalizacji(pozycjax + 1)(pozycjay))
            End If
            If listagracza.Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) Then
                listaliniowych.Add(listaLokalizacji(pozycjax)(pozycjay + 1))
            End If
            If listagracza.Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) Then
                listaliniowych.Add(listaLokalizacji(pozycjax)(pozycjay - 1))
            End If
        Next

        For k As Integer = 0 To listaliniowych.Count - 1
            If Not listazlapanych.Contains(listaliniowych(k)) Then
                Dim pozycjax As Integer = 0
                Dim pozycjay As Integer = 0
                For i As Integer = 0 To listaLokalizacji.Count - 1
                    For j As Integer = 0 To listaLokalizacji(i).Count - 1
                        If listaLokalizacji(i)(j).Name = listaliniowych(k).Name Then
                            pozycjax = i
                            pozycjay = j
                        End If
                    Next
                Next
                If listaliniowych.Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) And Not _
listazlapanych.Contains(listaLokalizacji(pozycjax - 1)(pozycjay)) Then
                    listaLiniwszystkich.Add(Tuple.Create(listaliniowych(k), listaLokalizacji(pozycjax - 1)(pozycjay)))
                End If
                If listaliniowych.Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) And Not _
listazlapanych.Contains(listaLokalizacji(pozycjax + 1)(pozycjay)) Then
                    listaLiniwszystkich.Add(Tuple.Create(listaliniowych(k), listaLokalizacji(pozycjax + 1)(pozycjay)))
                End If
                If listaliniowych.Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) And Not _
listazlapanych.Contains(listaLokalizacji(pozycjax)(pozycjay + 1)) Then
                    listaLiniwszystkich.Add(Tuple.Create(listaliniowych(k), listaLokalizacji(pozycjax)(pozycjay + 1)))
                End If
                If listaliniowych.Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) And Not _
listazlapanych.Contains(listaLokalizacji(pozycjax)(pozycjay - 1)) Then
                    listaLiniwszystkich.Add(Tuple.Create(listaliniowych(k), listaLokalizacji(pozycjax)(pozycjay - 1)))
                End If
                If listaliniowych.Contains(listaLokalizacji(pozycjax - 1)(pozycjay - 1)) And _
Not listazlapanych.Contains(listaLokalizacji(pozycjax - 1)(pozycjay - 1)) Then
                    listaLiniwszystkich.Add(Tuple.Create(listaliniowych(k), listaLokalizacji(pozycjax - 1)(pozycjay - 1)))
                End If
                If listaliniowych.Contains(listaLokalizacji(pozycjax + 1)(pozycjay + 1)) And _
Not listazlapanych.Contains(listaLokalizacji(pozycjax + 1)(pozycjay + 1)) Then
                    listaLiniwszystkich.Add(Tuple.Create(listaliniowych(k), listaLokalizacji(pozycjax + 1)(pozycjay + 1)))
                End If
                If listaliniowych.Contains(listaLokalizacji(pozycjax - 1)(pozycjay + 1)) And _
Not listazlapanych.Contains(listaLokalizacji(pozycjax - 1)(pozycjay + 1)) Then
                    listaLiniwszystkich.Add(Tuple.Create(listaliniowych(k), listaLokalizacji(pozycjax - 1)(pozycjay + 1)))
                End If
                If listaliniowych.Contains(listaLokalizacji(pozycjax + 1)(pozycjay - 1)) And _
Not listazlapanych.Contains(listaLokalizacji(pozycjax + 1)(pozycjay - 1)) Then
                    listaLiniwszystkich.Add(Tuple.Create(listaliniowych(k), listaLokalizacji(pozycjax + 1)(pozycjay - 1)))
                End If
            End If
        Next

        'rysujemy kółeczka i linie
        For i As Integer = 0 To listaLiniwszystkich.Count - 1
            listaLiniwszystkich(i).Item1.Visible = False
            listaLiniwszystkich(i).Item2.Visible = False
            Application.DoEvents()
            If gracz Then
                Dim myPen As Pen = New Pen(zielony, 2)
                d.DrawLine(myPen, listaLiniwszystkich(i).Item1.Location.X + 10, _
listaLiniwszystkich(i).Item1.Location.Y + 10, listaLiniwszystkich(i).Item2.Location.X + 10, _
listaLiniwszystkich(i).Item2.Location.Y + 10)
                d.FillEllipse(zielony, New Rectangle(listaLiniwszystkich(i).Item1.Location.X + 5, _
listaLiniwszystkich(i).Item1.Location.Y + 5, 10, 10))
                d.FillEllipse(zielony, New Rectangle(listaLiniwszystkich(i).Item2.Location.X + 5, _
listaLiniwszystkich(i).Item2.Location.Y + 5, 10, 10))
            Else
                Dim myPen As Pen = New Pen(czerwony, 2)
                d.DrawLine(myPen, listaLiniwszystkich(i).Item1.Location.X + 10, _
listaLiniwszystkich(i).Item1.Location.Y + 10, listaLiniwszystkich(i).Item2.Location.X + 10, _
listaLiniwszystkich(i).Item2.Location.Y + 10)
                d.FillEllipse(czerwony, New Rectangle(listaLiniwszystkich(i).Item1.Location.X + 5, _
listaLiniwszystkich(i).Item1.Location.Y + 5, 10, 10))
                d.FillEllipse(czerwony, New Rectangle(listaLiniwszystkich(i).Item2.Location.X + 5, _
listaLiniwszystkich(i).Item2.Location.Y + 5, 10, 10))
            End If
        Next

    End Sub

Pętla ta wymaga trochę jeszcze pracy ale jej założenia są chyba jasne.

Gotowy projekt dostępny pod adresem: GraWkropki_visualmonsters.cba.pl

Sam kod programu do pobrania: Kropki visualmonsters.cba.pl

 

Permalink do tego artykułu: https://visualmonsters.cba.pl/gra-w-kropki/

Dodaj komentarz

Twój adres email nie będzie publikowany.