Układanka

Dzisiaj zrobimy sobie prostą, lecz bardzo ciekawą układankę, podejrzałem ją bardzo dawno, była częścią zestawu gier pewnej aplikacji. Dodałem ją do programu Brain Pop Up:

Prosta i bardzo fajna gra, która uczy strategi i planowania.
To zaczynamy:

 

Rodzaj elementu Nazwa elementu Ustawienia
Form Form1 Name: Form1
Text: JigSaw
Size: 734;831
StartPosition: CenterScreen
Icon: 
TableLayoutPanel TableLayoutPanel1 Dock: Fill
Collection:
-Row1:  192
-Row2: 100%
Panel PanelTop Dock: Fill
Panel PanelBottom Dock: FIll
Panel  mainBoard Name: mainBoard
BackColor: White
Location: 111;19
Size: 465;453
Panel sampleFirst Name: sampleFirst
BackColor: White
Location: 320;25
Size: 153;142
Panel sampleSecond Name: sampleSecond
BackColor: White
Location: 494;25
Size: 153;142
Panel firstLeftTop Parent: sampleFirstName: firstLeftTop
BackColor: White
Location: 9;9
Size:67;62
Panel firstLeftBottom Parent: sampleFirst
Name: firstLeftBottom
BackColor: White
Location: 9;70
Size:67;62
Panel firstRightTop Parent: sampleFirst
Name: firstRightTop
BackColor: White
Location: 76;9
Size:67;62
Panel firstRightBottom Parent: sampleFirst
Name: firstRightBottom
BackColor: White
Location: 76;70
Size:67;62
Panel firstMiddle Parent: sampleFirst
Name: firstMiddle
BackColor: Black
Location: 69;64
Size:13;12
Panel secondLeftTop Parent: sampleSecond
Name: secondLeftTop
BackColor: White
Location: 9;9
Size: 67;62
Panel secondRightTop Parent: sampleSecond
Name: secondRightTop
BackColor: White
Location: 76; 9
Size: 67;62
Panel secondLeftBottom Parent: sampleSecond
Name: secondLeftBottom
BackColor: White
Location: 9; 70
Size: 67;62
Panel secondRightBottom Parent: sampleSecond
Name: secondRightBottom
BackColor: White
Location: 76; 70
Size: 67;62
Panel secondMiddle Parent: sampleSecond
Name: secondMiddle
BackColor: Black
Location: 69;64
Size:13;12
Panel hiddenLeftTop Name: hiddenLeftTop
Location: 665; 34
Visible: False
Panel hiddenLeftBottom Name: hiddenLeftBottom
Location: 665; 95
Visible: False
Panel hiddenRightTop Name: hiddenRightTop
Location: 703; 34
Visible: False
Panel hiddenRightBottom Name: hiddenRightBottom
Location: 703; 95
Visible: False
Label Label_points Name: Label_points
Location: 13; 14
Size: 127; 81
ForeColor: Black
Font: Arial; 15,75pt; style=Bold
Text: Punkty:
TextAlign: MiddleRight
Label Label_steps Name: Label_steps
Location: 10; 76
Size: 127; 81
ForeColor: Black
Font: Arial; 15,75pt; style=Bold
Text: Krok:
TextAlign: MiddleRight
Label points Name: points
Location: 136; 14
Size: 121; 81
ForeColor: Red
Font: Microsoft Sans Serif; 21,75pt;style=Bold
Text: 0
TextAlign: MiddleLeft
Label steps Name: steps
Location: 135; 76
Size: 121; 81
ForeColor: Black
Font: Microsoft Sans Serif; 21,75pt;style=Bold
Text: 0
TextAlign: MiddleLeft
PictureBox startPB Parent: mainBoard
Name: startPB
Location: 169; 340
Size: 330; 132
SizeMode: Zoom
Image: image

Jak będzie wyglądała nasza gra:

No to zaczynamy. Powyższa instrukcja ustawi początkowe elementy Formy, a nasz projekt będzie składał się z dwóch elementów, Formy i Jigsaw class

Po ułożeniu wszystkich elementów kod naszej formy będzie bardzo prosty:

Public Class Form1
    Private Sub PictureBox1_Click_1(sender As Object, e As EventArgs) _
        Handles startPB.Click
        startPB.Visible = False

        Dim jigsaw As New jigsaw(mainBoard,
                             PanelTop,
                             firstLeftTop,
                             firstLeftBottom,
                             firstRightTop,
                             firstRightBottom,
                             secondLeftTop,
                             secondLeftBottom,
                             secondRightTop,
                             secondRightBottom,
                             2,
                             hiddenLeftTop,
                             hiddenRightTop,
                             hiddenLeftBottom,
                             hiddenRightBottom,
                             1,
                             points,
                             steps)

        PanelTop.Enabled = True
    End Sub
End Class

Na pierwszym etapie naszego tutoriala będziemy generować plansze do gry, poniższy kod nie zawiera zaawansowanych elementów, jego opis znajdziecie w kodzie mimo, że jest długi zawiera zmienne potrzebne do ustawienia i obsługi elementów rozgrywki.

Public Class jigsaw

    Dim random As New Random
    Private WithEvents Timer1 As New Timer With {.Interval = 10}

    'przechowuje siatkę planszy głównej
    Dim backgroundPanelsList As New List(Of Tuple(Of Panel, Integer, Integer))
    Dim backgroundColor As Color = Color.White 'kolor pól na planszy
    'przechowuje listę czarnych punktów na planszy
    Dim blackPointsPanelsList As New List(Of Tuple(Of String, Integer, Integer))

    'główna plansza gry
    Private WithEvents mainBoard As New Panel
    'panel który zawiera punkty, wzory itp
    Private WithEvents PanelTop As New Panel

    'pierwszy wzór
    Private WithEvents firstLeftTop As New Panel
    Private WithEvents firstLeftBottom As New Panel
    Private WithEvents firstRightTop As New Panel
    Private WithEvents firstRightBottom As New Panel

    'drugi wzór
    Private WithEvents secondLeftTop As New Panel
    Private WithEvents secondLeftBottom As New Panel
    Private WithEvents secondRightTop As New Panel
    Private WithEvents secondRightBottom As New Panel

    'elementy pomocnicze
    Private WithEvents hiddenLeftTop As New Panel
    Private WithEvents hiddenRightTop As New Panel
    Private WithEvents hiddenLeftBottom As New Panel
    Private WithEvents hiddenRightBottom As New Panel

    'lewel gry, odpowiada za wielkość planszy
    Private level As Integer

    Dim points As Double = 0
    Dim steps As Integer = 0

    Dim labelSteps As Label
    Dim labelPoints As Label

    Public Sub New(ByRef mainBoard As Panel,
                   ByRef PanelTop As Panel,
                   ByRef firstLeftTop As Panel,
                   ByRef firstLeftBottom As Panel,
                   ByRef firstRightTop As Panel,
                   ByRef firstRightBottom As Panel,
                   ByRef secondLeftTop As Panel,
                   ByRef secondLeftBottom As Panel,
                   ByRef secondRightTop As Panel,
                   ByRef secondRightBottom As Panel,
                   ByVal _level As Integer,
                   ByRef hiddenLeftTop As Panel,
                   ByRef hiddenRightTop As Panel,
                   ByRef hiddenLeftBottom As Panel,
                   ByRef hiddenRightBottom As Panel,
                   ByVal proc As Double,
                   ByRef points As Label,
                   ByRef steps As Label)

        _mainBoard = mainBoard
        _PanelTop = PanelTop

        _firstLeftTop = firstLeftTop
        _firstLeftBottom = firstLeftBottom
        _firstRightTop = firstRightTop
        _firstRightBottom = firstRightBottom

        _secondLeftTop = secondLeftTop
        _secondLeftBottom = secondLeftBottom
        _secondRightTop = secondRightTop
        _secondRightBottom = secondRightBottom

        _hiddenLeftTop = hiddenLeftTop
        _hiddenRightTop = hiddenRightTop
        _hiddenLeftBottom = hiddenLeftBottom
        _hiddenRightBottom = hiddenRightBottom

        labelSteps = steps
        labelPoints = points
        level = _level
        generateMainBoard(proc)

    End Sub


    Public Sub generateMainBoard(ByVal proc As Double)

        labelSteps.Text = steps.ToString
        labelPoints.Text = points.ToString

        Dim width As Integer = 3 + level
        Dim height As Integer = 3 + level

        If (PanelTop.Location.Y + PanelTop.Height + 5) + height * (50 * proc) + (48 * proc) _
            > mainBoard.Parent.Height Then
            Do
                height -= 1
                width += 1
                If (PanelTop.Location.Y + PanelTop.Height + 5) + height * (50 * proc) + (48 * proc) _
                    < mainBoard.Parent.Height Then
                    Exit Do
                End If
            Loop
        End If

        'ustawia wielkość głównej planszy do gry na postawie wysokości i szerokości
        'dodatkowo używamy procentu który może być użyteczny do jednolitego zwiększenia bądź zmniejszenia planszy
        mainBoard.Size = New Size(width * (50 * proc) + (48 * proc), height * (50 * proc) + (48 * proc))
        'Ładnie ustawi lokalizacje głównej planszy gry na środku
        mainBoard.Location = New Point((mainBoard.Parent.Width - mainBoard.Width) / 2,
                                       (mainBoard.Parent.Height - mainBoard.Height) / 2)

        'Czarne punkty na planszy
        For i As Integer = 0 To width - 1
            For j As Integer = 0 To height - 1
                Dim blackPoints As New Panel
                blackPoints.Location = New Point((45 * proc) + i * (49 * proc), (45 * proc) + j * (49 * proc))
                blackPoints.Size = New Size((10 * proc), (10 * proc))
                blackPoints.BackColor = Color.Black
                blackPoints.Cursor = Cursors.Hand
                blackPoints.Name = "panL_" + i.ToString + j.ToString
                'obsługuje kliknięcie w panel
                AddHandler blackPoints.Click, AddressOf blackPoints_Click
                'wyswietla duchy po wejściu kursorem w czarny punkt
                AddHandler blackPoints.MouseEnter, AddressOf pan_enter
                'wygasza duchy po wyjściu z punktu
                AddHandler blackPoints.MouseLeave, AddressOf pan_leave
                'dodaje nasz punkt do listy
                blackPointsPanelsList.Add(Tuple.Create(blackPoints.Name, i, j))
                'dodaje nasz czarny punkt na plansze
                mainBoard.Controls.Add(blackPoints)
            Next
        Next
        'Siatka na planszy
        For i As Integer = 0 To width
            For j As Integer = 0 To height
                Dim web As New Panel
                web.Location = New Point(1 + i * (49 * proc), 1 + j * (49 * proc))
                web.BackColor = backgroundColor
                web.Size = New Size((49 * proc), (49 * proc))
                web.Name = "pan_" + i.ToString + j.ToString
                'ten panel będzie miał wiele zastosowań, będzie wyswietlał duchy i przechowywał 
                'punkty dodane odjęte itp
                backgroundPanelsList.Add(Tuple.Create(web, i, j))
                web.BorderStyle = BorderStyle.FixedSingle
                'dodaje siatkę na planszę gry
                mainBoard.Controls.Add(web)
            Next
        Next
        'losuje wzory
        patternDrawing(firstLeftTop, firstLeftBottom, firstRightTop, firstRightBottom, 255)
        patternDrawing(secondLeftTop, secondLeftBottom, secondRightTop, secondRightBottom, 100)

    End Sub

    'Te elementy będą potrzebne na dalszym etapie
    Private Sub pan_leave(sender As Object, e As EventArgs)

    End Sub

    Private Sub pan_enter(sender As Object, e As EventArgs)

    End Sub

    Private Sub blackPoints_Click(sender As Object, e As EventArgs)

    End Sub

    Private Sub patternDrawing(ByRef pan1 As Panel, ByRef pan2 As Panel, ByRef pan3 As Panel,
                               ByRef pan4 As Panel, ByVal brightness As Integer)

    End Sub
End Class

 

Pierwszy element jest konstruktorem, który zainicjuje nasz projekt. Po uruchomieniu nasza plansza nie będzie jeszcze wyglądała okazale, ale spokojnie, będziemy powoli dodawać do niej funkcjonalność.

Zajmiemy się wszystkimi tymi elementami z osobna. Najpierw musimy się zastanowić ile możliwości ustawienia naszego wzoru mamy, jeśli nasz wzór tworzymy z trzech elementów wtedy mamy tylko cztery możliwości jego ułożenia:

Innych możliwości nie ma a zmniejszenie ilości wypełnionych kwadratów, czyli wprowadzenie dodatkowych wzorów zepsułoby przyjemność gry i ułatwiłoby znacząco rozgrywkę. Nasz wybór określimy za pomocą metody:

        Dim wybor As Integer = random.Next(0, 4)

Mówi on nam, że wybiera losowo element od zera do 3. Następnie tworzymy listę kolorów, które następnie będziemy wybierać losowo. Aby podnieść poziom trudności, warto dodać nowe kolory, trudniej jest połączyć sześć czy siedem kolorów niż cztery. Ma to również znaczenie, gdy mamy dużą planszę, więcej kolorów komplikuje grę.

#Region "Losowanie wzoru"
    Private Sub patternDrawing(ByRef pan1 As Panel, ByRef pan2 As Panel, ByRef pan3 As Panel,
                               ByRef pan4 As Panel, ByVal brightness As Integer)

        'zeruje kolor pól
        pan1.BackColor = backgroundColor
        pan2.BackColor = backgroundColor
        pan3.BackColor = backgroundColor
        pan4.BackColor = backgroundColor

        'Lista kolorów z których będzie układany wzór
        Dim colorsList As New List(Of Color)
        colorsList.Add(Color.FromArgb(100, 187, 132))
        colorsList.Add(Color.FromArgb(94, 193, 235))
        colorsList.Add(Color.FromArgb(217, 187, 213))
        colorsList.Add(Color.FromArgb(245, 209, 13))
        'komplikuje gre dy level/wielkość planszy jest większa
        If level > 3 Then
            colorsList.Add(Color.FromArgb(235, 131, 60))
        End If
        If level > 5 Then
            colorsList.Add(Color.FromArgb(239, 150, 144))
        End If

        'kontrola duplikatów kolorów, nie możemy dopuścić aby kolory się zduplikowały
        Dim duplicateControl As New List(Of Boolean)
        For i As Integer = 0 To 3
            duplicateControl.Add(False)
        Next

        'wybór naszego wzoru
        Select Case random.Next(0, 4)
            Case 0
                '11
                '10
                pan1.BackColor = randomChoice(duplicateControl, brightness, colorsList)
                pan2.BackColor = randomChoice(duplicateControl, brightness, colorsList)
                pan3.BackColor = randomChoice(duplicateControl, brightness, colorsList)
            Case 1
                '10
                '11
                pan1.BackColor = randomChoice(duplicateControl, brightness, colorsList)
                pan2.BackColor = randomChoice(duplicateControl, brightness, colorsList)
                pan4.BackColor = randomChoice(duplicateControl, brightness, colorsList)
            Case 2
                '01
                '11
                pan2.BackColor = randomChoice(duplicateControl, brightness, colorsList)
                pan3.BackColor = randomChoice(duplicateControl, brightness, colorsList)
                pan4.BackColor = randomChoice(duplicateControl, brightness, colorsList)
            Case 3
                '11
                '01
                pan1.BackColor = randomChoice(duplicateControl, brightness, colorsList)
                pan3.BackColor = randomChoice(duplicateControl, brightness, colorsList)
                pan4.BackColor = randomChoice(duplicateControl, brightness, colorsList)
        End Select
    End Sub

    Function randomChoice(duplicateControl As List(Of Boolean), brightness As Integer,
                          colorsList As List(Of Color)) As Color
        Do
            Dim rand As Integer = random.Next(0, colorsList.Count)
            If duplicateControl(rand) = False Then
                duplicateControl(rand) = True
                'wybiera kolor i opuszcza pętle
                Return Color.FromArgb(brightness, colorsList(rand))
            End If
        Loop
    End Function
#End Region

Efekt będzie następujący:

Zajmiemy się teraz kolejnym elementem naszej gry, czyli widmem naszych wzorów. Plan jest prosty, dla ułatwienia rozgrywki wprowadzimy element, który będzie wizualizował nam nasze wzory na planszy. Nasz obiekt będziemy, ustawia za pomocą koordynatów czarnego punktu:

Bierzemy koordynaty czarnego punktu, w tym wypadku (0,0) i dodajemy, a to do pierwszej wartości, a to do drugiej i ostatecznie do obu, sprawdzając wszystkie opcje na około. Nasza logika sprawdzi, czy ułożenie elementu jest możliwe, jeśli tak to wyświetli je na podstawie wzoru:

#Region "wizualizacja wzoru"
    Dim ghost1 As New Panel
    Dim ghost2 As New Panel
    Dim ghost3 As New Panel
    Dim ghost4 As New Panel

    Private Sub pan_enter(sender As Object, e As EventArgs)
        'wyczyść panele
        cleanGhosts()
        'przechowuje koordynaty naszego wyboru
        Dim localization_1 As Integer
        Dim localization_2 As Integer
        'przeszukuje listę czarnych punktów w poszukiwaniu tego wybranego
        For i As Integer = 0 To blackPointsPanelsList.Count - 1
            If blackPointsPanelsList(i).Item1 = DirectCast(sender, Panel).Name Then
                localization_1 = blackPointsPanelsList(i).Item2
                localization_2 = blackPointsPanelsList(i).Item3
                Exit For
            End If
        Next
        'ten element sprawdza czy ułożenie naszego elementu jest możliwe,
        'jeśli tak to przechodzi do wyświetlenia go na planszy
        If checkPossibility(localization_1, localization_2) = True Then
            'ta logika sprawdza nasz wzór w sekcji wyświetlonych elementów do ułożenia
            If Not firstLeftTop.BackColor = backgroundColor Then
                ghost1 = setColor(0, 0, localization_1, localization_2, firstLeftTop)
            End If
            If Not firstLeftBottom.BackColor = backgroundColor Then
                ghost2 = setColor(0, 1, localization_1, localization_2, firstLeftBottom)
            End If
            If Not firstRightTop.BackColor = backgroundColor Then
                ghost3 = setColor(1, 0, localization_1, localization_2, firstRightTop)
            End If
            If Not firstRightBottom.BackColor = backgroundColor Then
                ghost4 = setColor(1, 1, localization_1, localization_2, firstRightBottom)
            End If
        End If
    End Sub

    Function setColor(plusX As Integer, plusY As Integer, localization_1 As Integer,
                      localization_2 As Integer, targetPanel As Panel) As Panel
        'kiedy przechodzimy na planze, nasze elementy są wyszukiwane na liście za pomocą 
        'koordynatów naszego małego czarnego kwadratu
        For i As Integer = 0 To backgroundPanelsList.Count - 1
            If backgroundPanelsList(i).Item2 = localization_1 + plusX And
                backgroundPanelsList(i).Item3 = localization_2 + plusY Then

                backgroundPanelsList(i).Item1.BackColor = Color.FromArgb(100, targetPanel.BackColor)
                Return backgroundPanelsList(i).Item1
            End If
        Next
        Return New Panel
    End Function

    Private Sub pan_leave(sender As Object, e As EventArgs)
        cleanGhosts()
    End Sub

    Private Sub cleanGhosts()
        ghost1.BackColor = backgroundColor
        ghost2.BackColor = backgroundColor
        ghost3.BackColor = backgroundColor
        ghost4.BackColor = backgroundColor
    End Sub

#End Region

#Region "Sprawdza czy mozna wyświetlić obiekt"
    Private Function checkPossibility(ByVal localization_1 As Integer,
                                      ByVal localization_2 As Integer) As Boolean
        Dim possibility As Boolean = True

        If Not firstLeftTop.BackColor = backgroundColor Then
            possibility = test(0, 0, localization_1, localization_2, firstLeftTop)
            If Not possibility Then
                Return possibility
            End If
        End If
        If Not firstLeftBottom.BackColor = backgroundColor Then
            possibility = test(0, 1, localization_1, localization_2, firstLeftBottom)
            If Not possibility Then
                Return possibility
            End If
        End If
        If Not firstRightTop.BackColor = backgroundColor Then
            possibility = test(1, 0, localization_1, localization_2, firstRightTop)
            If Not possibility Then
                Return possibility
            End If
        End If
        If Not firstRightBottom.BackColor = backgroundColor Then
            possibility = test(1, 1, localization_1, localization_2, firstRightBottom)
            If Not possibility Then
                Return possibility
            End If
        End If
        Return possibility
    End Function

    Function test(plusX As Integer, plusY As Integer, localization_1 As Integer,
                  localization_2 As Integer, targetPanel As Panel) As Boolean

        For i As Integer = 0 To backgroundPanelsList.Count - 1
            If backgroundPanelsList(i).Item2 = localization_1 + plusX And
                backgroundPanelsList(i).Item3 = localization_2 + plusY Then
                If backgroundPanelsList(i).Item1.BackColor = backgroundColor Or
                    backgroundPanelsList(i).Item1.BackColor =
                            Color.FromArgb(100, targetPanel.BackColor) Then
                    Exit For
                Else
                    Return False
                End If
            End If
        Next
        Return True
    End Function
#End Region

Co zasługuje tutaj na uwagę to pobieranie koordynatów czarnego elementu. Jak pamiętacie, do każdego elementu dodaliśmy koordynaty w liście „blackPointsPanelsList”:

Przeszukujemy naszą listę paneli i w momencie zgodności nazw elementów pobieramy koordynaty.

Używając:

DirectCast(sender, Panel)

Wybiera on nam kliknięty element. Możemy rozpatrywać wskazany obiekt Panel i wszystkie jego elementy. Efekt będzie imponujący:

Jak już możemy podglądać elementy, przyszedł czas na ich ułożenie.

#Region "efekt kliku"
    Dim occupiedFields As New List(Of Tuple(Of Panel, Color))

    Public Sub blackPoints_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
        'dodaj i wyświetl krok
        steps += 1
        labelSteps.Text = steps.ToString
        'ustaw lokalizacje do dalszych czynności
        For i As Integer = 0 To blackPointsPanelsList.Count - 1
            If blackPointsPanelsList(i).Item1 = DirectCast(sender, Panel).Name Then
                localization_1 = blackPointsPanelsList(i).Item2
                localization_2 = blackPointsPanelsList(i).Item3
                Exit For
            End If
        Next
        'sprawdź czy można kliknąć
        If checkPossibility(localization_1, localization_2) Then
            occupiedFields.Clear()
            If Not firstLeftTop.BackColor = backgroundColor Then
                occupiedFields.Add(setOccupiedField(0, 0, localization_1, localization_2, firstLeftTop))
            End If
            If Not firstLeftBottom.BackColor = backgroundColor Then
                occupiedFields.Add(setOccupiedField(0, 1, localization_1, localization_2, firstLeftBottom))
            End If
            If Not firstRightTop.BackColor = backgroundColor Then
                occupiedFields.Add(setOccupiedField(1, 0, localization_1, localization_2, firstRightTop))
            End If
            If Not firstRightBottom.BackColor = backgroundColor Then
                occupiedFields.Add(setOccupiedField(1, 1, localization_1, localization_2, firstRightBottom))
            End If
            'dodaj kolory na planszy
            timeCounter = 0
            Timer1.Start()
            'przesuń wzór
            movePattern()
            'dodaj nowy wzór
            patternDrawing(secondLeftTop, secondRightTop, secondLeftBottom, secondRightBottom, 100)

            ghost1 = hiddenLeftTop
            ghost2 = hiddenRightTop
            ghost3 = hiddenLeftBottom
            ghost4 = hiddenRightBottom
        End If

    End Sub

    Function setOccupiedField(plusX As Integer, plusY As Integer, localization_1 As Integer,
                              localization_2 As Integer, targetPanel As Panel) As Tuple(Of Panel, Color)
        For i As Integer = 0 To backgroundPanelsList.Count - 1
            If backgroundPanelsList(i).Item2 = localization_1 + plusX And
                backgroundPanelsList(i).Item3 = localization_2 + plusY Then
                Return Tuple.Create(backgroundPanelsList(i).Item1, targetPanel.BackColor)
                Exit For
            End If
        Next
        Return Nothing
    End Function

    Dim timeCounter As Integer = 0

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        timeCounter += 50
        If timeCounter >= 255 Then
            Timer1.Stop()
            For i As Integer = 0 To occupiedFields.Count - 1
                occupiedFields(i).Item1.BackColor = occupiedFields(i).Item2
            Next
            sameColors(localization_1, localization_2)
            ' Sprawdza czy to juz koniec gry
            Dim boolList As New List(Of Boolean)

            For i As Integer = 0 To blackPointsPanelsList.Count - 1
                'dla każdego czarnego elementu sprawdzamy możliwość ułożenia wzoru
                boolList.Add(gameOver(blackPointsPanelsList(i).Item2, blackPointsPanelsList(i).Item3,
                                               firstLeftTop, firstLeftBottom, firstRightTop, firstRightBottom))
            Next
            'jesli koniec to zaczernia
            If Not boolList.Contains(True) Then
                'jeśli lista nie zawiera true (czyli możliwości ułożenia) 
                'wtedy zaczernij i zablokuj plansze
                For i As Integer = 0 To backgroundPanelsList.Count - 1
                    If backgroundPanelsList(i).Item1.BackColor = backgroundColor Then
                        backgroundPanelsList(i).Item1.BackColor = Color.Black
                    End If
                Next
                mainBoard.Enabled = False
            End If
            ''''''''''''''''''''''''''''''''
        Else
            For i As Integer = 0 To occupiedFields.Count - 1
                'odsłania ułożony element
                occupiedFields(i).Item1.Refresh()
                occupiedFields(i).Item1.BackColor = Color.FromArgb(timeCounter, occupiedFields(i).Item2)
            Next
        End If

    End Sub
#End Region

#Region "Sprawdza czy koniec gry"
    Private Function gameOver(ByVal localization_1 As Integer, ByVal localization_2 As Integer,
                              ByRef pan1 As Panel, ByRef pan2 As Panel, ByRef pan3 As Panel,
                              ByRef pan4 As Panel) As Boolean

        Dim effect As Boolean = True

        'dla każdego elementu wzoru sprawdzamy czy jest możliwość jego ułożenia w obrębie 
        'czarnego elementu 
        If Not pan1.BackColor = backgroundColor Then
            effect = possibilityTest(0, 0, localization_1, localization_2)
            'jeśli effect jest false wtedy przerywamy naszą funkcje i zwracamy,
            'że elementu nie da się ułożyć
            If Not effect Then
                Return effect
            End If
        End If
        If Not pan2.BackColor = backgroundColor Then
            effect = possibilityTest(0, 1, localization_1, localization_2)
            If Not effect Then
                Return effect
            End If
        End If
        If Not pan3.BackColor = backgroundColor Then
            effect = possibilityTest(1, 0, localization_1, localization_2)
            If Not effect Then
                Return effect
            End If
        End If
        If Not pan4.BackColor = backgroundColor Then
            effect = possibilityTest(1, 1, localization_1, localization_2)
            If Not effect Then
                Return effect
            End If
        End If
        Return effect
    End Function

    Function possibilityTest(plusX As Integer, plusY As Integer, localization_1 As Integer,
                             localization_2 As Integer) As Boolean
        For i As Integer = 0 To backgroundPanelsList.Count - 1
            If backgroundPanelsList(i).Item2 = localization_1 + plusX And
                backgroundPanelsList(i).Item3 = localization_2 + plusY Then
                If backgroundPanelsList(i).Item1.BackColor = backgroundColor Then
                Else
                    Return False
                    Exit For
                End If
            End If
        Next
        Return True
    End Function
#End Region

zamarkujmy sobie pewne elementy naszego kodu:

da nam to możliwość podejrzenia naszej zmiany w praktyce:

Sercem naszej aplikacji będzie właśnie metoda „blackPoints_Click” to ona wszystkim zarządza i pociąga za sznurki. Mogłoby się wydawać, że Timer odgrywa tu ważną rolę, lecz tak nie jest. Timer jest elementem dodatkowym, który ma na celu wytworzenie efektu pojawienia się, kolory powinny płynnie zwiększać swój odcień. Warto zaznaczyć w tym miejscu, że lista „occupiedFields” jest wykorzystywana w wymienionej wyżej operacji i nie odgrywa ważnej roli w całym procesie.

sprawdzimy teraz, czy nasza gra się już zakończyła:

#Region "Sprawdza czy koniec gry"
    Private Function gameOver(ByVal localization_1 As Integer, ByVal localization_2 As Integer,
                              ByRef pan1 As Panel, ByRef pan2 As Panel, ByRef pan3 As Panel,
                              ByRef pan4 As Panel) As Boolean

        Dim effect As Boolean = True

        'dla każdego elementu wzoru sprawdzamy czy jest możliwość jego ułożenia w obrębie 
        'czarnego elementu 
        If Not pan1.BackColor = backgroundColor Then
            effect = possibilityTest(0, 0, localization_1, localization_2)
            'jeśli effect jest false wtedy przerywamy naszą funkcje i zwracamy,
            'że elementu nie da się ułożyć
            If Not effect Then
                Return effect
            End If
        End If
        If Not pan2.BackColor = backgroundColor Then
            effect = possibilityTest(0, 1, localization_1, localization_2)
            If Not effect Then
                Return effect
            End If
        End If
        If Not pan3.BackColor = backgroundColor Then
            effect = possibilityTest(1, 0, localization_1, localization_2)
            If Not effect Then
                Return effect
            End If
        End If
        If Not pan4.BackColor = backgroundColor Then
            effect = possibilityTest(1, 1, localization_1, localization_2)
            If Not effect Then
                Return effect
            End If
        End If
        Return effect
    End Function

    Function possibilityTest(plusX As Integer, plusY As Integer, localization_1 As Integer,
                             localization_2 As Integer) As Boolean
        For i As Integer = 0 To backgroundPanelsList.Count - 1
            If backgroundPanelsList(i).Item2 = localization_1 + plusX And
                backgroundPanelsList(i).Item3 = localization_2 + plusY Then
                If backgroundPanelsList(i).Item1.BackColor = backgroundColor Then
                Else
                    Return False
                    Exit For
                End If
            End If
        Next
        Return True
    End Function
#End Region

w połączeniu z poprzednim elementem sprawdzimy wszystkie czarne punkty i możliwość ułożenia wzoru. Sprawdzamy wszystkie elementy, po kolei dopasowując i sprawdzając kolor pól.

 

Przesuńmy teraz nasze wzory w lewo:

#Region "przesowanie paneli"
    Private Sub movePattern()
        If secondLeftTop.BackColor = backgroundColor Then
            firstLeftTop.BackColor = backgroundColor
        Else
            firstLeftTop.BackColor = Color.FromArgb(255, secondLeftTop.BackColor)
        End If

        If secondLeftBottom.BackColor = backgroundColor Then
            firstLeftBottom.BackColor = backgroundColor
        Else
            firstLeftBottom.BackColor = Color.FromArgb(255, secondLeftBottom.BackColor)
        End If

        If secondRightTop.BackColor = backgroundColor Then
            firstRightTop.BackColor = backgroundColor
        Else
            firstRightTop.BackColor = Color.FromArgb(255, secondRightTop.BackColor)
        End If

        If secondRightBottom.BackColor = backgroundColor Then
            firstRightBottom.BackColor = backgroundColor
        Else
            firstRightBottom.BackColor = Color.FromArgb(255, secondRightBottom.BackColor)
        End If
    End Sub
#End Region

to da nam możliwość układania różnych wzorów na planszy:

Ostatnim elementem naszej układanki będzie zerowanie jednakowych elementów i przypisywanie punktów. Jak będziemy sprawdzać nasze elementy? Otóż dostęp do ułożonego wzory będziemy mieli swobodny dlatego dla każdego ułożonego elementu, jeśli nie będzie miał on koloru tła, będziemy sprawdzać element pod nim, nad nim, z lewej strony i prawej.

tak wygląda kod który to sprawdzi:

#Region "sprawdza czy sa w poblizy takie same kolory"

    Dim clearColorList As New List(Of Panel)

    Private Sub sameColors(ByVal loc1 As Integer, ByVal loc2 As Integer)

        'Sprawdzamy każdy kwadracik ułożonego wzoru
        checkAround(loc1, loc2)
        checkAround(loc1 + 1, loc2)
        checkAround(loc1, loc2 + 1)
        checkAround(loc1 + 1, loc2 + 1)

        'zerujemy kolory z listy,
        'lista zawiera tylko te pozycje które mają być wyzerowane
        For i As Integer = 0 To clearColorList.Count - 1
            clearColorList(i).BackColor = backgroundColor
        Next

        'sprawdzi ile jest wyjątkowych niepowtarzających się elementów
        'i doda tyle punktów
        points += clearColorList.Distinct.Count()

        labelPoints.Text = Math.Floor(points).ToString
        clearColorList.Clear()
    End Sub

    Private Sub checkAround(ByVal loc1 As Integer, ByVal loc2 As Integer)
        Dim MyPanelColor As Color
        Dim myPanel As New Panel

        'określamy parametry naszego elementu który będziemy sprawdzać
        'pobieramy jego kolor i jego samego
        For i As Integer = 0 To backgroundPanelsList.Count - 1
            If backgroundPanelsList(i).Item2 = loc1 And
                backgroundPanelsList(i).Item3 = loc2 Then
                MyPanelColor = backgroundPanelsList(i).Item1.BackColor
                myPanel = backgroundPanelsList(i).Item1
                Exit For
            End If
        Next

        'następnie jeśli nasz pobrany element ma kolor tła to nic nie będziemy robić
        'ponieważ był to element pusty
        If Not MyPanelColor = backgroundColor Then
            'najpierw sprawdzamy wszystkie opcje poziomo
            For i As Integer = loc1 - 1 To loc1 + 1
                'wykluczamy element środkowy
                If Not i = loc1 Then
                    'pobieramy kolor skrajnych elementów
                    For k As Integer = 0 To backgroundPanelsList.Count - 1
                        'sprawdzamy koordynaty czy się zgadzają
                        If backgroundPanelsList(k).Item2 = i And
                            backgroundPanelsList(k).Item3 = loc2 Then
                            'jeśli natrafimy na nasz element
                            If backgroundPanelsList(k).Item1.BackColor = MyPanelColor Then
                                'jeśli koroy się zgadzają
                                'dodajemy nasz panel do wyzerowania i element skrajny
                                clearColorList.Add(myPanel)
                                clearColorList.Add(backgroundPanelsList(k).Item1)
                            End If
                            'opuszczamy tą pętle aby nie tracić czasu
                            Exit For
                        End If
                    Next
                End If
            Next
            For i As Integer = loc2 - 1 To loc2 + 1
                If Not i = loc2 Then
                    For k As Integer = 0 To backgroundPanelsList.Count - 1
                        If backgroundPanelsList(k).Item2 = loc1 And
                            backgroundPanelsList(k).Item3 = i Then
                            If backgroundPanelsList(k).Item1.BackColor = MyPanelColor Then
                                clearColorList.Add(myPanel)
                                clearColorList.Add(backgroundPanelsList(k).Item1)
                            End If
                            Exit For
                        End If
                    Next
                End If
            Next
        End If
    End Sub
#End Region

Nasza gra jest już gotowa:

Wisienką na torcie będzie ramka naszych elementów wzoru:

#Region "ramka wzoru"
    Private Sub Panel_1_Paint(sender As Object, e As PaintEventArgs) Handles firstLeftTop.Paint
        If Not firstLeftTop.BackColor = backgroundColor Then
            ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, Color.DarkGray, ButtonBorderStyle.Solid)
        End If
    End Sub
    Private Sub Panel_2_Paint(sender As Object, e As PaintEventArgs) Handles firstLeftBottom.Paint
        If Not firstLeftBottom.BackColor = backgroundColor Then
            ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, Color.DarkGray, ButtonBorderStyle.Solid)
        End If
    End Sub
    Private Sub Panel_3_Paint(sender As Object, e As PaintEventArgs) Handles firstRightTop.Paint
        If Not firstRightTop.BackColor = backgroundColor Then
            ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, Color.DarkGray, ButtonBorderStyle.Solid)
        End If
    End Sub
    Private Sub Panel_4_Paint(sender As Object, e As PaintEventArgs) Handles firstRightBottom.Paint
        If Not firstRightBottom.BackColor = backgroundColor Then
            ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, Color.DarkGray, ButtonBorderStyle.Solid)
        End If
    End Sub
    Private Sub secondLeftTop_Paint(sender As Object, e As PaintEventArgs) Handles secondLeftTop.Paint
        If Not secondLeftTop.BackColor = backgroundColor Then
            ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, Color.LightGray, ButtonBorderStyle.Solid)
        End If
    End Sub
    Private Sub secondLeftBottom_Paint(sender As Object, e As PaintEventArgs) Handles secondLeftBottom.Paint
        If Not secondLeftBottom.BackColor = backgroundColor Then
            ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, Color.LightGray, ButtonBorderStyle.Solid)
        End If
    End Sub
    Private Sub secondRightTop_Paint(sender As Object, e As PaintEventArgs) Handles secondRightTop.Paint
        If Not secondRightTop.BackColor = backgroundColor Then
            ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, Color.LightGray, ButtonBorderStyle.Solid)
        End If
    End Sub
    Private Sub secondRightBottom_Paint(sender As Object, e As PaintEventArgs) Handles secondRightBottom.Paint
        If Not secondRightBottom.BackColor = backgroundColor Then
            ControlPaint.DrawBorder(e.Graphics, e.ClipRectangle, Color.LightGray, ButtonBorderStyle.Solid)
        End If
    End Sub
#End Region

Nasz wzór otrzyma stylową ramkę:

Wygląda na to, że już skończyliśmy naszą grę, pełen kod pobrać można z mojego GitHuba: https://github.com/VisualMonsters/JigSaw

lub dla nie lubiących Gita można pobrać zipa:  Jigsaw

Permalink do tego artykułu: https://visualmonsters.cba.pl/ukladanka/

Dodaj komentarz

Twój adres email nie będzie publikowany.