A Simple Yet Classic Game With a Wee Twist

J.C. SolvoTerra 1 Tallied Votes 315 Views Share

NOTE: The games GUI is not fully implemented, so changing it's image and difficulty is done manually in the Button.Click Event

NOTE: Whether you download the VS2013 source file or copy and paste the code, you need to download, and extract the two image files to the project's "Bin\Debug" directory.

If you copy and paste the source ensure your form has the following controls:

Button (Button1)
PictureBox (Name:pbGameBoard, Width:792, Height:792)

THE GAME

This is a fun example using graphics. It is a representation of the classic tile slide game, where you slide the tiles around to make the picture. This version is a little different. There are Tiles and Sub Tiles. The Tile Grid is 9 x 9. Each Tile has a 9 x 9 Sub Tile Grid.

If you set the game to Easy then only the main Tiles are scrambled. If it is set to Medium then not only are the Tiles scrambled but so are their sub tiles.

Instead of sliding the tiles around, this game is actually switching tiles\subtiles with the adjacent tile\subtile. Subtiles cannot be switched with subtiles from a different tile.

HOW TO PLAY

To Start A New Game:
Click your button

To Move Tiles:
Select the center SubTile of The Tile you want to move. The SubTile will be selected in Green. Move the mouse to the center SubTile of an adjacent tile and the cursor will turn yellow. If you click now, the two Tiles will be switched.

Image Dificulty:Easy
26e1e303be98882d0e343a8335bb0f3e

To Move SubTiles:
SubTiles can only be moved around within their parent tile. Select any SubTile by clicking on it. Move your mouse over and adjacent SubTile in the same Tile, the cursor box will go green. Click now and the two subtiles will be switched.

Image Difficulty:Easy
501b1073df32eaca05133627ec7e647c

Move Not Allowed:
If your cursor box goes red then this simply means a switch cannot be made.

Image Difficulty:Easy
b53441509cca01367f909b67276e2f52

Cancel Your Selection.
Press the right mouse button.

Select Dificulty

See Difficulty In Button.Click Event. The only available options at the moment are Easy or Medium.

Image Difficulty:Medium
16e69d263cd7bb6252505f90fca7071a

Select Image

Set The GameBoards Index to 0 or 1 in the Button.Click Event

Begginnerdev commented: Very nice post! +9
'USE THE SOURCE
'### Make Sure Your Form Has A Button (Button1) and a picturebox (Name:pbGameBoard, Width:792, Height:792)
'###Download The Two Image Zip Files And Extract Them To The Project's Bin\Debug Directory.

'DOWNLOAD THE SOURCE
'Alternatively Download The Source Zip (RevealMe.Zip). You Still Need To Download And Paste The Image
Files Into The Bin\Debug Directory Due To Upload File Size Limits.

'Form Code

Public Class Form1

    Private WithEvents CurrentGame As RevealMe

    Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click

        'Set Difficulty Here (Easy, Medium, Hard [Not Applied])
        Dim Difficulty As RevealMe.Difficulty = RevealMe.Difficulty.Medium


        Dim GameBoards As String() = {Application.StartupPath & _
                                   "\WheresWalley.jpg",
                                      Application.StartupPath & _
                                   "\WarGames.jpg"}

        'Choose GameBoards Index 0 or 1
        CurrentGame = New RevealMe(GameBoards(1), pbGameBoard, Difficulty)

        AddHandler CurrentGame.Complete, AddressOf GameComplete

    End Sub

    Private Sub GameComplete()

        RemoveHandler CurrentGame.Complete, AddressOf GameComplete
        MsgBox("Well Done! You Did It.", vbOKOnly + vbInformation, "Game Over")

    End Sub

    Private Sub pbGameBoard_MouseDown(sender As Object, e As MouseEventArgs) Handles pbGameBoard.MouseDown

        If e.Button = Windows.Forms.MouseButtons.Left Then
            If Not (IsNothing(CurrentGame)) Then CurrentGame.SelectBlock(e.X, e.Y)
        Else
            If Not (IsNothing(CurrentGame)) Then CurrentGame.CancelSelection()
        End If

    End Sub

    Private Sub pbGameBoard_MouseMove(sender As Object, e As MouseEventArgs) Handles pbGameBoard.MouseMove

        If Not (IsNothing(CurrentGame)) Then CurrentGame.DrawCursor(e.X, e.Y)

    End Sub

End Class

'Game Class

Public Class RevealMe

    Public Event Complete()

    Private Enum CursorTypes

        Normal = 0
        Block = 1
        SubBlock = 2
        NotAllowed = 3

    End Enum

    Public Enum Difficulty

        Easy = 0
        Medium = 1
        Hard = 2

    End Enum

    Private Class Selected
        Public Block As Point
        Public SubBlock As Point

        Public Function BlockIndex() As Integer
            Return (Block.Y * 3) + Block.X
        End Function

        Public Function SubBlockIndex() As Integer
            Return (SubBlock.Y * 3) + SubBlock.X
        End Function

    End Class

    Private SwitchOK As Boolean = False
    Private SelectedIndex As Selected

    Private GameImage As Bitmap
    Private InGameImage As Bitmap

    Private GameData As Integer(,)
    Private GameData1_9 As List(Of Integer(,))

    Private GameBoard As PictureBox = Nothing
    Private GameDifficulty As Difficulty

    Public Sub New(ImageFile As String, ByRef BoardContainer As PictureBox, Difficulty As Difficulty)

        Randomize()

        GameDifficulty = Difficulty

        GameImage = Bitmap.FromFile(ImageFile)

        GameData = New Integer(8, 8) {}

        For Index As Integer = 0 To 80

            GameData(Index Mod 9, Index \ 9) = Index

        Next

        GameBoard = BoardContainer

        ScrambleImage()

        GameBoard.Image = GetGameBoard()

    End Sub

    Public Sub ScrambleImage()

        ExtractSubBlocks()

        If Not (GameDifficulty = Difficulty.Easy) Then ScrambleSubBlocks()

        ScrambleBlocks()
        WriteSubBlocks()

        GameBoard.Image = GetGameBoard()

    End Sub

    Private Sub ScrambleSubBlocks()

        Dim DataSeg(9) As Integer
        Dim Indexes As New List(Of Integer)
        Dim rndIndex As Integer = 0

        For SubBlock As Integer = 0 To 8

            For SegY = 0 To 2
                For SegX = 0 To 2
                    Indexes.Add(GameData1_9(SubBlock)(SegX, SegY))
                Next
            Next

            For SegY = 0 To 2
                For SegX = 0 To 2
                    rndIndex = Rnd() * (Indexes.Count - 1)
                    GameData1_9(SubBlock)(SegX, SegY) = Indexes(rndIndex)
                    Indexes.RemoveAt(rndIndex)
                Next
            Next

        Next

    End Sub

    Private Sub ScrambleBlocks()

        Dim Indexes As New List(Of Integer)({0, 1, 2, 3, 4, 5, 6, 7, 8})
        Dim GD1_9 As New List(Of Integer(,))

        Dim rndIndex As Integer = 0

        For LP = 0 To 8

            rndIndex = Rnd() * (Indexes.Count - 1)

            GD1_9.Add(GameData1_9(Indexes(rndIndex)))
            Indexes.RemoveAt(rndIndex)
        Next

        GameData1_9 = New List(Of Integer(,))(GD1_9)

    End Sub


    Private Sub ExtractSubBlocks()

        GameData1_9 = New List(Of Integer(,))

        Dim DataSeg As Integer(,) = Nothing

        For BlockY = 0 To 6 Step 3
            For BlockX = 0 To 6 Step 3

                DataSeg = New Integer(2, 2) {}

                For SegY = 0 To 2
                    For SegX = 0 To 2
                        DataSeg(SegX, SegY) = GameData(BlockX + SegX, BlockY + SegY)
                    Next
                Next

                GameData1_9.Add(DataSeg)

            Next
        Next

    End Sub

    Private Function  WriteSubBlocks() As boolean

        Dim BlockPos As Point = Nothing

        For Block = 0 To 8

            BlockPos = New Point(Block Mod 3, Block \ 3)

            For SegY = 0 To 2
                For SegX = 0 To 2
                    GameData((BlockPos.X * 3) + SegX, (BlockPos.Y * 3) + SegY) =
                        GameData1_9(Block)(SegX, SegY)
                Next
            Next

        Next

        For Indexer = 0 To 80
            If GameData(Indexer Mod 9, Indexer \ 9) <> Indexer Then
                Return False
            End If
        Next

        Return True

    End Function

    Private Function GetGameBoard() As Bitmap

        Dim BMP_Board As New Bitmap(792, 792)
        Dim GFX_Board As Graphics = Graphics.FromImage(BMP_Board)

        Dim SourceRectangle As Rectangle = Nothing
        Dim SourceCoords As Point = Nothing

        Dim SelectedPen As New Pen(Brushes.Green, 2)

        For GDatY As Integer = 0 To 8
            For GDatX As Integer = 0 To 8


                SourceCoords = New Point()
                SourceCoords.X = (GameData(GDatX, GDatY) Mod 9) * 88
                SourceCoords.Y = (GameData(GDatX, GDatY) \ 9) * 88

                GFX_Board.DrawImage(GameImage, New Rectangle(GDatX * 88, GDatY * 88, 88, 88),
                                    New Rectangle(SourceCoords, New Size(88, 88)),
                                    GraphicsUnit.Pixel)

            Next
        Next

        If Not (IsNothing(SelectedIndex)) Then
            GFX_Board.DrawRectangle(SelectedPen,
                                    New Rectangle((SelectedIndex.Block.X * 264) +
                                                  (SelectedIndex.SubBlock.X * 88),
                                                  (SelectedIndex.Block.Y * 264) +
                                                  (SelectedIndex.SubBlock.Y * 88), 87, 87))
        End If

        GFX_Board.Dispose()
        GC.Collect()

        InGameImage = BMP_Board

        Return BMP_Board

    End Function

    Public Sub SelectBlock(X As Integer, Y As Integer)

        Dim Complete As Boolean

        If IsNothing(SelectedIndex) Then

            SelectedIndex = GetBlockIndex(X, Y)

        ElseIf SwitchOK = True Then

            Dim OverIndex = GetBlockIndex(X, Y)
            Dim CurrentCursorType As CursorTypes = GetCursorType(X, Y)

            Select Case CurrentCursorType
                Case CursorTypes.Block

                    Dim PlaceHolder As Integer(,) = GameData1_9(SelectedIndex.BlockIndex)
                    GameData1_9(SelectedIndex.BlockIndex) = GameData1_9(OverIndex.BlockIndex)
                    GameData1_9(OverIndex.BlockIndex) = PlaceHolder

                Case CursorTypes.SubBlock

                    Dim PlaceHolder As Integer = GameData1_9(SelectedIndex.BlockIndex)(SelectedIndex.SubBlock.X, SelectedIndex.SubBlock.Y)
                    GameData1_9(SelectedIndex.BlockIndex)(SelectedIndex.SubBlock.X, SelectedIndex.SubBlock.Y) = GameData1_9(OverIndex.BlockIndex)(OverIndex.SubBlock.X, OverIndex.SubBlock.Y)
                    GameData1_9(OverIndex.BlockIndex)(OverIndex.SubBlock.X, OverIndex.SubBlock.Y) = PlaceHolder

            End Select

            Complete = WriteSubBlocks()

            SelectedIndex = Nothing

        Else

            SelectedIndex = Nothing

        End If

        GameBoard.Image = GetGameBoard()

        If Complete Then
            RaiseEvent Complete()
        End If

    End Sub

    Public Sub CancelSelection()

        SelectedIndex = Nothing

        GameBoard.Image = GetGameBoard()

    End Sub

    Public Sub DrawCursor(X As Integer, Y As Integer)

        Dim BMP_Board As New Bitmap(InGameImage)
        Dim GFX_Board As Graphics = Graphics.FromImage(BMP_Board)

        Dim CurrentCursorType As CursorTypes = GetCursorType(X, Y)

        Dim CursorPen As Pen = Nothing

        Select Case CurrentCursorType
            Case CursorTypes.Normal

                CursorPen = New Pen(Brushes.Green, 2)
                SwitchOK = False

            Case CursorTypes.Block

                CursorPen = New Pen(Brushes.Yellow, 2)
                SwitchOK = True

            Case CursorTypes.SubBlock

                CursorPen = New Pen(Brushes.Green, 2)
                SwitchOK = True

            Case CursorTypes.NotAllowed

                CursorPen = New Pen(Brushes.Red, 2)
                SwitchOK = False

        End Select


        GFX_Board.DrawRectangle(CursorPen,
                       New Rectangle((X \ 88) * 88,
                                      (Y \ 88) * 88, 87, 87))


        GFX_Board.Dispose()

        GameBoard.Image = BMP_Board
        GC.Collect()

    End Sub

    Private Function GetBlockIndex(X As Integer, Y As Integer) As Selected

        Return New Selected With {.Block = New Point(X \ 264, Y \ 264),
                                  .SubBlock = New Point((X Mod 264) \ 88, (Y Mod 264) \ 88)}

    End Function

    Private Function GetCursorType(X As Integer, Y As Integer) As CursorTypes

        Dim OverIndex As Selected = GetBlockIndex(X, Y)

        If IsNothing(SelectedIndex) Then

            Return CursorTypes.Normal

        Else

            If Math.Abs((OverIndex.SubBlock.X - SelectedIndex.SubBlock.X) +
                        (OverIndex.SubBlock.Y - SelectedIndex.SubBlock.Y)) = 1 And
                        OverIndex.BlockIndex = SelectedIndex.BlockIndex Then

                Return CursorTypes.SubBlock

            End If

            If SelectedIndex.SubBlockIndex = 4 And OverIndex.SubBlockIndex = 4 Then

                If SelectedIndex.Block.X = OverIndex.Block.X Then

                    If SelectedIndex.Block.Y = OverIndex.Block.Y + 1 Or _
                        SelectedIndex.Block.Y = OverIndex.Block.Y - 1 Then

                        Return CursorTypes.Block

                    End If

                ElseIf SelectedIndex.Block.Y = OverIndex.Block.Y Then

                    If SelectedIndex.Block.X = OverIndex.Block.X + 1 Or _
                        SelectedIndex.Block.X = OverIndex.Block.X - 1 Then

                        Return CursorTypes.Block

                    End If

                End If

            End If

        End If

        Return CursorTypes.NotAllowed

    End Function

End Class
J.C. SolvoTerra 109 Eat, Sleep, Code, Repeat Featured Poster

Where's Walley Easy:

454850e0d8da1800414ba8ab7c268b3d

Where's Walley Medium:
8f18b339ef1742230854e2cbda54ef38

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.