Introduction
Hello again! Today I will try to explain how to create a word search game with Visual Basic.NET. In case you don’t know what a Word Search game is, have a look at this Wikipedia Article.
Our Project
Shaken not stirred. Seeing the fact that the James Bond Movie franchise turned 50 early in October, I have decided to use the James Bond movie titles as the theme for our little complicated project. I have always loved James Bond movies, so I am actually quite excited about our little mission here. MI 6 called. Get your funky gadgets from Q (make sure there is a decent magnifying glass in there as well), and let us start our mission!
Design
As you know, M is quite old fashioned and strict. She won’t be too concerned about our design, as long as our code works. We do have license to do what we want with the design, but since James is always in trouble nowadays, let’s keep it very very basic; after all, it is how the code works that gets our job done.
Start a new Visual Basic Windows Forms Project, name it SpyGame, or licenseToSearch; just make sure it adheres to Bond’s character.
Add the following controls to your form and set their properties appropriately:
| Control | Property | Setting |
| Form1 | Name | frmSearch |
| Size | 834, 532 | |
| Text | HTG Word Search | |
| WindowState | Maximized | |
| Panel | Name | pnlGrid |
| Dock | Left | |
| Size | 518, 380 | |
| Label | Name | lblITBF |
| Dock | Top | |
| Location | 518, 0 | |
| Text | “” | |
| Panel | Name | pnlItems |
| Location | 518, 26 | |
| Size | 308, 363 | |
| Panel | Name | Panel1 |
| Dock | Bottom | |
| Label | Name | lblTimeLeft |
| AutoSize | True | |
| BorderStyle | FixedSingle | |
| Location | 10, 12 ( Inside Panel 1 ) | |
| Label | Name | lblScore |
| Location | 93, 12 ( Inside Panel 1 ) | |
| Size | 706, 103 | |
| Button | Name | btnStart |
| Location | 12, 75 ( Inside Panel 1 ) | |
| Text | Start | |
| Timer | Name | tmrCountDown |
| Interval | 1000 |
It doesn’t look like much, but as I said, you do have license to turn it into something nicer.
Code
Action time, and as you know, our friend 007 always has a plan! Let’s start with the variables and move systematically through all of the necessary code, just as Bond would do. Add the following variables in your General Declarations:
Private arrBonds(23) As String 'Array of Bond Movies
Private arrItems(23) As Label 'Array of Lables
Private strScramble As String = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" 'Each Char of the Alphabet - To Fill In Blanks
Private lblSel As String 'Selected Label's Text
Private blnStart As Boolean 'Start Button Clicked?
Private intScore As Integer 'Score
Private intItemsFound As Integer 'Total Items Found
Private timeEnd As DateTime 'Calculates Ending Time
Private timeDiff As TimeSpan 'Difference Between Start and End Times
Private intTimeBonus As Integer 'Time bonus
Our next step is to add our grid. This comprises 900 blocks ( 30 x 30 ), luckily this is not a mine-field… yet. Add the next sub:
Public Sub DrawLabelGrid() 'Draws Grid of 900 blocks - 30 x 30
Dim NewLoc As New Point 'Location of Each New Block
For CurrRow As Integer = 0 To 29 'Row By Row
For CurrCol As Integer = 0 To 29 'Column In Row By Column In Row
NewLoc.X = 2 + CurrRow * 15 'Height Of Block
NewLoc.Y = 2 + CurrCol * 15 'Width Of Block
Dim lbl As New Label 'New Label
With lbl 'Set Properties
.Name = CurrRow.ToString() & "_" & CurrCol.ToString 'Name Ex: 1_2 ( Row 1 _ Col 2 )
.BorderStyle = BorderStyle.FixedSingle 'Block Effect
.Location = NewLoc 'Set Position
.Width = 15 'Width
.Height = 15 'Height
.TextAlign = ContentAlignment.MiddleCenter 'Text Alignment
.BackColor = System.Drawing.Color.White 'BackColour
.Font = New Font("Arial", 8, FontStyle.Bold) 'Font Style
AddHandler lbl.MouseClick, AddressOf lbl_MouseClick 'Event Handler Click
' AddHandler lbl.MouseDown, AddressOf lbl_MouseDown
'AddHandler lbl.MouseMove, AddressOf lbl_MouseMove
' AddHandler lbl.MouseUp, AddressOf lbl_MouseUp
End With
Me.pnlGrid.Controls.Add(lbl) 'Add Labels
Next
Next
lblITBF.Text = "Items to find: " & Environment.NewLine & Environment.NewLine 'Items To Find Label
End Sub
OK, why so many blocks? Well, it seems as if our mission was compromised a bit, with some Bond Movie titles being extremely long–the longest being On Her Majesty’s Secret Service. Sans spaces and apostrophes, it totals 26 characters. If our grid was 26 * 26, it would have been too obvious. Granted, most word search games aren’t this big with so many letters, but this is a Bond mission, and it has to be tough!
What was done in the DrawLabelGrid sub was to create the rows and columns by using a dynamic label with set properties. You will also notice the event handler that was added. The reason for this is so that we can work with these labels during game play.
Add the Form Load event:
Private Sub frmHTGWordSearch_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
DrawLabelGrid() 'Draw Grid
arrBonds(0) = "DRNO" 'West
arrBonds(1) = "FROMRUSSIAWITHLOVE" 'East
arrBonds(2) = "GOLDFINGER" 'East
arrBonds(3) = "ONHERMAJESTYSSECRETSERVICE" 'South
arrBonds(4) = "DIAMONDSAREFOREVER" 'West
arrBonds(5) = "MOONRAKER" 'SouthEast
arrBonds(6) = "FORYOUREYESONLY" 'West
arrBonds(7) = "GOLDENEYE" 'North
arrBonds(8) = "TOMORROWNEVERDIES" 'North
arrBonds(9) = "DIEANOTHERDAY" 'South
arrBonds(10) = "CASINOROYALE" 'NorthWest
arrBonds(11) = "SKYFALL" 'SouthWest
arrBonds(12) = "THUNDERBALL" 'South
arrBonds(13) = "YOUONLYLIVETWICE" 'South
arrBonds(14) = "LIVEANDLETDIE" 'East
arrBonds(15) = "THEMANWITHTHEGOLDENGUN" 'West
arrBonds(16) = "THESPYWHOLOVEDME" 'East
arrBonds(17) = "OCTOPUSSY" 'NorthEast
arrBonds(18) = "NEVERSAYNEVERAGAIN" 'South
arrBonds(19) = "AVIEWTOAKILL" 'South
arrBonds(20) = "THELIVINGDAYLIGHTS" 'North
arrBonds(21) = "licenseTOKILL" 'SouthEast
arrBonds(22) = "THEWORLDISNOTENOUGH" 'North
arrBonds(23) = "QUANTUMOFSOLACE" 'North
blnStart = False
End Sub
In the Form_Load event, we call the DrawLabelGrid sub, and initialize our Bond array with all of the Bond movie titles. Many a James Bond fan would argue that there are only 23 Bond movies. I always disagree. A not so well known Bond movie is entitled : Never Say Never Again, starring Sean Connery (the best Bond ever). This movie was produced by a different production studio than all of the others. This confusion causes people to say that it doesn’t actually count as a Bond film, but it does.
You will also notice that all of these array elements do not contain any space or special character. This is very important, because that can make the game too easy.
Now, the tricky part!
There are a total of 8 different directions in which we can populate our letters in the grid. We have the 4 cardinal directions ( North, East, South, West ) then we have the 4 intercardinal, or ordinal directions (North-East, South-East, South-West, North-West ). Have a look at Figure 1 below:

Figure 1 – Directions
Our starting point with all directions would be the middle point. This means that our words must start from there and continue in its associated direction. Let’s start with the cardinal directions first. Add the following subs:
Private Sub FillEast(ByVal strLetters As String, ByVal strRowEnd As String, ByVal intColStart As Integer) 'Fill Blocks From Left To Right
Dim i As Integer = 0 'Loop Counter
Dim charArr() As Char = strLetters.ToCharArray 'Break Letters Appart
For Each Ll As Label In pnlGrid.Controls 'Loop Through Grid
If Ll.Name.ToString().StartsWith(intColStart + i & "_") Then 'Determine What Number Name Starts With ( Column )
If Ll.Name.ToString().EndsWith(strRowEnd) Then 'Determine What Number Name Ends With ( Row )
If i <= charArr.Length - 1 Then 'Loop Through Character Array
Ll.Text = charArr(i).ToString 'Set The Text of Grid Blocks
i += 1
End If
End If
End If
Next
End Sub
Private Sub FillWest(ByVal strLetters As String, ByVal strRowEnd As String, ByVal intColStart As Integer) 'Fill Blocks From Right To Left
Dim i As Integer = 0
Dim charArr() As Char = strLetters.ToCharArray
Array.Reverse(charArr) 'Reverse String
For Each Ll As Label In pnlGrid.Controls
If Ll.Name.ToString().StartsWith(intColStart + i & "_") Then
If Ll.Name.ToString().EndsWith(strRowEnd) Then
If i <= charArr.Length - 1 Then
Ll.Text = charArr(i).ToString
i += 1
End If
End If
End If
Next
End Sub
Private Sub FillNorth(ByVal strLetters As String, ByVal intRowEnd As Integer, ByVal strColStart As String) 'Upwards
Dim i As Integer = 0
Dim charArr() As Char = strLetters.ToCharArray
Array.Reverse(charArr)
For Each Ll As Label In pnlGrid.Controls
If Ll.Name.ToString().StartsWith(strColStart) Then
If Ll.Name.ToString().EndsWith("_" & intRowEnd + i) Then
If i <= charArr.Length - 1 Then
Ll.Text = charArr(i).ToString
i += 1
End If
End If
End If
Next
End Sub
Private Sub FillSouth(ByVal strLetters As String, ByVal intRowEnd As Integer, ByVal strColStart As String) 'Downwards
Dim i As Integer = 0
Dim charArr() As Char = strLetters.ToCharArray
For Each Ll As Label In pnlGrid.Controls
If Ll.Name.ToString().StartsWith(strColStart) Then
If Ll.Name.ToString().EndsWith("_" & intRowEnd + i) Then
If i <= charArr.Length - 1 Then
Ll.Text = charArr(i).ToString
i += 1
End If
End If
End If
Next
End Sub
With your quick (golden)eye you can see the resemblance in all of the subs. Each sub has three arguments / parameters – Letters, RowEnd, and ColStart. Letters would be the array element passed to it, which gets broken apart with the use of a character array. RowEnd Identifies the last part of the particular gridblock’s name, and ColStart identifies the first part of the gridblock’s name – that is the whole reasoning behind giving the block with the Column and Row indicators. You, as the local hero need to decipher this name and use it. 🙂
We loop through each gridblock and determine the start and end of the name. Why? So that we know which direction the words must flow. If you take a close look at FillEast, you will see that the row number stays the same, but the columns increment. In FillWest, we Reverse the Letters string, then decrement the Column numbers and the row still remains the same. In FillSouth, the rows increment and the Rows stay the same, whereas FillNorth is just the opposite.
Not so complicated now is it?! Nope 🙂
The intercardinal directions are a bit more complicated. The logic remains the same, but both the column and row indicators need to increment or decrement simultaneously. Let us have a look.
Private Sub FillNorthWest(ByVal strLetters As String, ByVal intRowEnd As Integer, ByVal intColStart As Integer) 'Up & Left
Dim i As Integer = 0
Dim charArr() As Char = strLetters.ToCharArray
Array.Reverse(charArr)
For Each Ll As Label In pnlGrid.Controls
If Ll.Name.ToString().StartsWith(intColStart + i & "_") Then
If Ll.Name.ToString().EndsWith("_" & intRowEnd + i) Then
If i <= charArr.Length - 1 Then
Ll.Text = charArr(i).ToString
i += 1
End If
End If
End If
Next
End Sub
Private Sub FillNorthEast(ByVal strLetters As String, ByVal intRowEnd As Integer, ByVal intColStart As Integer) 'Up & Right
Dim i As Integer = 0
Dim charArr() As Char = strLetters.ToCharArray
For Each Ll As Label In pnlGrid.Controls
If Ll.Name.ToString().StartsWith(intColStart + i & "_") Then
If Ll.Name.ToString().EndsWith("_" & intRowEnd - i) Then
If i <= charArr.Length - 1 Then
Ll.Text = charArr(i).ToString
i += 1
End If
End If
End If
Next
End Sub
Private Sub FillSouthWest(ByVal strLetters As String, ByVal intRowEnd As Integer, ByVal intColStart As Integer) 'Down & Left
Dim i As Integer = 0
Dim charArr() As Char = strLetters.ToCharArray
Array.Reverse(charArr)
For Each Ll As Label In pnlGrid.Controls
If Ll.Name.ToString().StartsWith(intColStart + i & "_") Then
If Ll.Name.ToString().EndsWith("_" & intRowEnd - i) Then
If i <= charArr.Length - 1 Then
Ll.Text = charArr(i).ToString
i += 1
End If
End If
End If
Next
End Sub
Private Sub FillSouthEast(ByVal strLetters As String, ByVal intRowEnd As Integer, ByVal intColStart As Integer) 'Down & Right
Dim i As Integer = 0
Dim charArr() As Char = strLetters.ToCharArray
For Each Ll As Label In pnlGrid.Controls
If Ll.Name.ToString().StartsWith(intColStart + i & "_") Then
If Ll.Name.ToString().EndsWith(intRowEnd + i) Then
If i <= charArr.Length - 1 Then
Ll.Text = charArr(i).ToString
i += 1
End If
End If
End If
Next
End Sub
Inside FillNorthWest, we reverse our supplied string and increment the column and row indicators. FillNorthEast increments the Column and decrements the rows. SouthWest is the opposite of NorthEast and SouthEast is the opposite of NorthWest.
Add the following code to btnStart_Click:
Private Sub btnStart_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnStart.Click
blnStart = True 'Start Button Clicked
'Fill Blocks
FillEast(arrBonds(14), "_6", 8) 'Live and Let Die
FillEast(arrBonds(1), "_17", 9) 'From Russia With Love
FillEast(arrBonds(16), "_29", 0) 'The Spy Who Loved Me
FillEast(arrBonds(2), "_29", 20) 'Goldfinger
FillWest(arrBonds(15), "_1", 0) 'The Man With the Golden Gun
FillWest(arrBonds(0), "_7", 17) 'Dr. No
FillWest(arrBonds(4), "_26", 3) 'Diamonds Are Forever
FillWest(arrBonds(6), "_28", 4) 'For Your Eyes Only
FillNorth(arrBonds(22), 8, "1_") 'The World is Not Enough
FillNorth(arrBonds(8), 8, "4_") 'Tomorrow Never Dies
FillNorth(arrBonds(23), 11, "9_") 'Quantum of Solace
FillNorth(arrBonds(7), 10, "11_") 'GoldenEye
FillNorth(arrBonds(20), 1, "28_") 'The Living Daylights
FillNorthWest(arrBonds(10), 14, 5) 'Casino Royale
FillNorthEast(arrBonds(17), 15, 20) 'Octopussy
FillSouth(arrBonds(3), 0, "0_") 'On Her Majesty's Secret Service
FillSouth(arrBonds(18), 1, "3_") 'Never Say Never Again
FillSouth(arrBonds(13), 0, "7_") 'You Only Live Twice
FillSouth(arrBonds(19), 1, "17_") 'A View To A Kill
FillSouth(arrBonds(9), 16, "20_") 'Die Another Day
FillSouth(arrBonds(12), 17, "21_") 'Thunderball
FillSouthEast(arrBonds(21), 9, 16) 'license To Kill
FillSouthEast(arrBonds(5), 17, 12) 'Moonraker
FillSouthWest(arrBonds(11), 14, 12) 'Skyfall
End Sub
Here, we just supply the necessary coordinates and strings to each of our subs. You will notice that not every “Filling” sub has the same amount of strings supplied. This logic took me a while to finish honestly. 🙂
Once run and the Start button are clicked, your screen would resemble Figure 2.

Figure 2 – Our Bond Titles
Not bad at all! Good work so far 007!
The next code segment completes our grid. Let’s add the Scramble sub now:
Private Sub Scramble() 'Fill In Blank Blocks Randomly
Dim i As Integer = 0 'Start Index
Dim RandGen As New Random(Now.Millisecond) 'Generate Random Number
Dim charArr() As Char = strScramble.ToCharArray 'Break ABC String Apart Into Separate Chars
For Each Ll As Label In pnlGrid.Controls 'Loop Through Grid
Dim RandIndex As Integer = RandGen.Next(0, 25) 'Generate New Random Letter
If Ll.Text = "" OrElse Ll.Text = " " Then 'If Grid Block Is Empty or COntains A Space
Ll.Text = charArr(RandIndex).ToString 'Fill In Random Letter
End If
Next
End Sub
We break the strScramble string apart, then we determine whether or not the blocks in the grid have text. If they do not have text, we fill it with random letters produced by our Random object. Add the call to the Scramble sub in the click event of the start button. Your screen will look similar to Figure 3.

Figure 3 – Our completed grid
What is Left?
Well, not much for now. We need to have a list of items to find, else, unless you’re a Bond fanatic as I am, you will battle to find all the titles. We can add a scoring facility as well as a timer. Let’s complete this game now. Edit your code inside btnStartClick.
Private Sub btnStart_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles btnStart.Click
blnStart = True 'Start Button Clicked
'Fill Blocks
FillEast(arrBonds(14), "_6", 8) 'Live and Let Die
FillEast(arrBonds(1), "_17", 9) 'From Russia With Love
FillEast(arrBonds(16), "_29", 0) 'The Spy Who Loved Me
FillEast(arrBonds(2), "_29", 20) 'Goldfinger
FillWest(arrBonds(15), "_1", 0) 'The Man With the Golden Gun
FillWest(arrBonds(0), "_7", 17) 'Dr. No
FillWest(arrBonds(4), "_26", 3) 'Diamonds Are Forever
FillWest(arrBonds(6), "_28", 4) 'For Your Eyes Only
FillNorth(arrBonds(22), 8, "1_") 'The World is Not Enough
FillNorth(arrBonds(8), 8, "4_") 'Tomorrow Never Dies
FillNorth(arrBonds(23), 11, "9_") 'Quantum of Solace
FillNorth(arrBonds(7), 10, "11_") 'GoldenEye
FillNorth(arrBonds(20), 1, "28_") 'The Living Daylights
FillNorthWest(arrBonds(10), 14, 5) 'Casino Royale
FillNorthEast(arrBonds(17), 15, 20) 'Octopussy
FillSouth(arrBonds(3), 0, "0_") 'On Her Majesty's Secret Service
FillSouth(arrBonds(18), 1, "3_") 'Never Say Never Again
FillSouth(arrBonds(13), 0, "7_") 'You Only Live Twice
FillSouth(arrBonds(19), 1, "17_") 'A View To A Kill
FillSouth(arrBonds(9), 16, "20_") 'Die Another Day
FillSouth(arrBonds(12), 17, "21_") 'Thunderball
FillSouthEast(arrBonds(21), 9, 16) 'license To Kill
FillSouthEast(arrBonds(5), 17, 12) 'Moonraker
FillSouthWest(arrBonds(11), 14, 12) 'Skyfall
Scramble() 'Add Rest of Letters
Dim pntLoc As New Point 'Location of Items Labels
Dim i As Integer 'Loop Counter
For i = 0 To 23
arrItems(i) = New Label 'Create New Label And Set Appropriate Properties
arrItems(i).AutoSize = True
arrItems(i).Text = (i + 1).ToString & ") " & arrBonds(i) 'Add Items To Be Found Label Text
arrItems(i).Left = 30
arrItems(i).Top = i * 15
arrItems(i).BringToFront()
arrItems(i).Visible = True
pnlItems.Controls.Add(arrItems(i)) 'Add Items To Be Found
Next
timeEnd = DateTime.Now 'Get Current Time
Dim minute As Double = System.Convert.ToDouble(15) '15 Minutes
Dim second As Double = System.Convert.ToDouble(0) '0 Seconds
timeEnd = timeEnd.AddMinutes(minute) 'Add Mintues
timeEnd = timeEnd.AddSeconds(second) 'Add Seconds
tmrCountDown.Start() 'Start Temp Timer
btnStart.Enabled = False
End Sub
We fired two bullets with one shot here, as only Bond can! We created the list of items to be found, as well as started the timer object. 15 Minutes should be enough to complete the mission. Figure 4 shows our items.

Figure 4 – Our items to be found
Finding the items takes place in the lblMouseClick event.
Private Sub lbl_MouseClick(ByVal sender As Object, ByVal e As MouseEventArgs) 'Common Event Handler For Labels
Dim tempstr As String
Dim lblTemp As Label = DirectCast(sender, Label) 'Get Clicked Label
lblSel = lblSel & lblTemp.Text 'Concatenate Sequence of Letters
lblTemp.BackColor = Color.Gold 'Set Back Colour
Dim i As Integer
For i = 0 To arrBonds.Length - 1
Dim charArr() As Char = arrBonds(i).ToCharArray
Array.Reverse(charArr)
If lblSel = arrBonds(i) OrElse lblSel = charArr.ToString Then 'Determine Matches
arrBonds(i) = arrBonds(i) & " Found!" 'FOund
intScore += 20
intItemsFound += 1
lblScore.Text = "Items Found: " & intItemsFound & Environment.NewLine & _
"Score: " & intScore 'Increment Score
If intItemsFound >= 24 Then
ShowSummary() 'Game Completed
End If
tempstr = arrBonds(i)
arrItems(i).Text = tempstr
lblSel = "" 'Reset Everything For New Matches
tempstr = ""
End If
Next
End Sub
Once items are found, the score updates. On each click the color changes to gold. Yes, I could have used different logic here, but I wanted to keep it not too complicated. You have the licenseToChange.
The Timer_Tick event and ShowSummary sub follow:
Private Sub tmrCountDown_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles tmrCountDown.Tick
Dim strFinalOutput As String 'Output String
timeDiff = timeEnd - DateTime.Now
'Caclulate Difference Between Start and End
Dim output As TimeSpan = New TimeSpan(timeDiff.Hours, timeDiff.Minutes, timeDiff.Seconds)
strFinalOutput = "Time Left: " & output.ToString().Substring(3) 'Concatenates Time
lblTimeLeft.Text = strFinalOutput
If (timeDiff.Ticks < 0) Then 'If Time is Up
tmrCountDown.Stop()
MessageBox.Show("Time's UP!!")
ShowSummary()
btnStart.Enabled = True
End If
End Sub
Private Sub ShowSummary() 'Shows Summary After Game Completion
Dim strSummary As String 'Summary String
'Calculate Bonus For Minutes and Seconds Left
If timeDiff.Minutes > 0 Then
intTimeBonus = timeDiff.Minutes * 50
End If
If timeDiff.Seconds > 0 Then
intTimeBonus += timeDiff.Minutes * 20
End If
intScore += intTimeBonus 'Add To Score
'Compose String For Output
strSummary = "Summary" & Environment.NewLine & Environment.NewLine & _
"Items Found: " & intItemsFound.ToString & Environment.NewLine & Environment.NewLine & _
"TIME BONUS: " & intTimeBonus.ToString & Environment.NewLine & Environment.NewLine & _
"SCORE: " & intScore.ToString
lblScore.Text = strSummary 'Write Text
End Sub
Mission Complete
Play around with this game, the logic is there. Obviously there are far more better ways to accomplish this, but this is how my logic works. Play around, and don’t be afraid of letting me know what you have come up with!
If all items are found, the screen resembles Figure 5.

Figure 5 – Everything found
Conclusion
Thank you Mr. Bond for all your hard work during this article. I hope you have enjoyed this mission and that there are many more missions ahead for you. Sincerely, M.