Free Web Hosting Provider - Web Hosting - E-commerce - High Speed Internet - Free Web Page
Search the Web

    vbProgramming 
Tutorials - Tic Tac Toe
 
       
  vbProgramming Home :: vbProgramming Forums :: Tutorials :: Contact :: Links
 

 

          "Tic-Tac-Toe" - Your first game!


Mod.
How would you check what remainder a number has when you divide it? You use the Mod statement. Example:
13/2 is 6.5 - or 6 1/2.  What is the remainder? The remainder is 1 obviously. When you divide 13/2, you get 6, but you get a remainder of 1. Here is how its used: - Pretend X is 5:

If X Mod 2 = 1 Then
MessageBox.Show("The remainder of Dividing x by 2 is 1.")
End If

 Basically you are checking whether 5 divided by 2 is 1, and it is!

Why is this mod statement used? What is the purpose of doing this? OK, remember that any X "mod-ded" by 2 will be either 0 or 1. If you divide any number by 2, the remainder will either be 0, or 1. Example: 
3 Mod 2 = 1 
4 Mod 2 = 0  
5 Mod 2 = 1
6 Mod 2 = 0 

It keeps repeating. So, back to your question: What is this used for? Let's say you have a 2 player game. Instead of using the variable X, we will use the variable PlayerTurn, which will keep track of the player's turn! If you are making Tic-Tac-Toe, X goes first usually; if it is the second turn, O goes. If it is the 3rd turn X goes, 4th turn: O.. etc. Well, when its the first turn, PlayerTurn  = 1, when it is the 2nd turn PlayerTurn = 2. So on... We can say, when you Mod PlayerTurn by 2, if the remainder is 1, it is X's turn. If the remainder is 0, it is O's turn. Example:

If PlayerTurn Mod 2 = 1 Then
MessageBox.Show("X's Turn")
End If

If PlayerTurn Mod 2 = 0 Then
MessageBox.Show("Y's Turn")
End If

Below is a little chart of all the Mod statements. Whenever the result is 1, it is X's turn, if the result is 0, it is Y's turn. (assuming that X goes first, and that PlayerTurn starts with 1)

---
1 Mod 2 = 1  ' Basically, the remainder of 1/2 is (somehow) 1.   
2 Mod 2 = 0  ' My point is, if you Mod a number by 2, for every even number, the result is 0
3 Mod 2 = 1  ' For every odd number, the result is 1. Basically, we can say that if PlayerTurn is odd, it is 
4 Mod 2 = 0  'X's turn. If it is even, it is Y's turn. This keeps track of the players turn because you add 
5 Mod 2 = 1  'PlayerTurn by 1 at the end of each turn. Remember, in a game of Tic Tac Toe, there are only a
6 Mod 2 = 0  'maximum of 9 turns. It is easy to determine the winner,  But how will you determine
7 Mod 2 = 0  'if there is a tie? Well, the first thing you could do is check weather PlayerTurn 
8 Mod 2 = 0  'equals 9. But that wouldn't make sense. What if a player won during the 9th turn? This makes matters
9 Mod 2 = 0  'worse!! Well, here's a simple solution, if there is NO winner on the 9th turn, then its a tie. 

---


Setting it up

Enough explaining! Lets get on with our game! First create a project called TicTacToe. Remember that a TicTacToe board is square in shape, and it has 3 rows and 3 columns.  This means that in order for the form to look square in size, we need to make the width the same as the height. One thing we must note is that there are 3 columns and 3 rows. Which means that the form's width and height must be divisible by 3. So, make the form's size 450,450. 

Now, noting again that there are 3 squares and 3 columns, we must make our TicTacToe squares the same height and width. With simple math we can figure out that 450/3 is 150. So our TicTacToe squares are 150x150. What should we use for our TicTacToe squares? How about PictureBoxes? This is a really simple way of making TicTacToe.

This method gets VERY VERY messy. Here is my way of doing this: Create 1 PictureBox, set its size property to 150,150. Set its BackColor to something random (I used blue). You are setting its color temporarily because when you have 9 PictureBoxes the same color, you will get very confused and it will be very difficult to tell the difference between each (try it, and you'll see what I mean!). Set the PictureBox's Location property to 0,0. Remember, the location refers to the top-left pixel of the PictureBox, meaning that when you set the location to 0,0, the PictureBox will appear to be situated at the top-left of the form.

 Name this PictureBox sqr1_3. Here is the reason I named it this way. First of all, pretend the PictureBox is on the coordinate plane. We remember that the coordinate 1,3 means: move 1 to the right and move 3 up. If you picture a TicTacToe board, starting from the bottom left square, if you move 1 to the right (which IS the bottom left square) and move 3 up, you'll get to the top-left square.

We have placed our first TicTacToe square on the board. Follow the diagram for placing the rest (You don't have to use the same colors I used - remember the colors are there so you don't get confused!

 

 
Note: The coordinates that you see are the Location of the PictureBoxes.  The name that you see is the Name of the PictureBox. Also note that the sizes of the PictureBoxes are 150x150.



OK, now we are on the right track! We need to pick a color for all of  PictureBoxes. Let's pick black to be the color of the PictureBoxes. Click each PictureBox and set the BackColor property to Black. Now, when we play TicTacToe, we X or O appearing on the board. Well, how are we going to draw X or O? Easy! We simply draw it in Paint!  How simple could this be??

Open up Paint (Start | Run | type in "mspaint"). Once Paint is open, go to Image | Attributes (Ctrl + E) and set the Units to Pixels and set the Width and Height to 150. Make the background color of the image Black. Draw a white X on the Image. I suggest you draw a line going from the top-left of the image, to the bottom-right of the image; and draw a line going from the bottom-left of the image, to the top-right of the image. This will make it look "even" when you play the game! Save the image as "x.jpg". MAKE SURE YOU SAVE IT IN THE BIN DIRECTORY OF YOUR PROGRAM! (If you followed my directions, then it would be My Documents / Visual Studio Projects / TicTacToe/bin)

Create a New paint file with the Width and the Height being 150. Make the background color of the image black. Select the Hollow circle tool, and while holding shift, drag from the top-left to the bottom-right for a perfect circle! Save the image as "o.jpg". MAKE SURE YOU SAVE IT IN THE BIN DIRECTORY OF YOUR PROGRAM! (If you followed my directions, then it would be My Documents / Visual Studio Projects / TicTacToe / bin)

If you want, you can change the color of the PictureBoxes to a single color, but I would recommend doing this when you're done with the program. 


Coding the Program

Go to your code (F7). Declare a global variable (Global means that it is at the top of your code) at the top of your code, below Inherits System.Windows.Forms.Form. This shouldn't be a new concept, you have been declaring Global Variables throughout all these tutorials; I just introduced the term "Global" to you, that's all.  Go to  sqr1_1.Click, and type the code below:

If PlayerTurn Mod 2 = 0 Then
sqr1_1.Image = Image.FromFile("x.jpg") 
PlayerTurn += 1

ElseIf PlayerTurn Mod 2 = 1 Then
sqr1_1.Image = Image.FromFile("o.jpg")
PlayerTurn += 1

End
If

We looked at Mod earlier in the tutorial - we decided that if PlayerTurn Mod 2 = 0, then its X's turn. If it is 1, then it is O's turn. The next line sets the PictureBox's(sqr1_1) image to "x.jpg". We do not have to give it a specific directory name, like "C:/Program Files/ My Folder/ Another Folder / My Programs / Tic Tac Toe/ bin/ x.jpg", since it was in the Bin folder, we could just say "x.jpg".  We add PlayerTurn by 1 to "say" that that turn is over. Let's say it is turn 3, and it is O's turn; we change the PictureBox's picture to "o.jpg". We add PlayerTurn by 1 (which makes PlayerTurn = 4), to say, "Turn 3 is over because PlayerTurn is 4" 

Well, you have the meat of this tutorial done. Go to sqr1_2.Click and copy and paste the SAME code, EXCEPT change sqr1_1.Image to sqr1_2.Image. Do this for ALL squares. It should be easy, its just repetitive copying and pasting and editing.

Run your program! Click sqr1_1. Click it again! Wait a minute! Why does it change from X to O..... you don't want the Player to "change" his/her move, you want the move to be PERMANENT - this is OUTRAGEOUS! (A slight problem: You need to click the squares "slowly", because as I said before in a previous tutorial, PictureBoxes are slow.)

There are several ways we can go about letting the player to "click once", and not change a previous move. Here is an example:
 

 -  Create 9 Booleans whose names are similar to the square names:
    ClickedSquare1_1
    ClickedSquare1_2
    (so on, and so forth)
    
    When you change a square to X or O, that Boolean from that square is True. For example - if you clicked sqr1_1 and 
    changed it to X (or O), then ClickedSquare1_1 is set to True. 

    The square click event will only execute when that square's Boolean is False. For example, if ClickedSqr1_1 is set to True then that sqr1_1 will
not change its Picture (for instance, it will not change from X.bmp to O.bmp, or from O.bmp to
X.bmp.

Read the first line again: Create 9 Booleans whose names are similar to the square name. 
Who would want to create a huge mess by creating NINE Booleans? It takes up too much space! It gets annoying!

Solution: USE ARRAYS

An Array is basically a grid. If you create a 10 by 10 array, basically you are creating a 10 by 10 grid. If you create a 3 by 3 array, then you are creating a 3 by 3 grid... What looks like a 3 by 3 grid? Well, a Tic Tac Toe board of course!

When you create an Array, you are not creating a grid in the sense that you see it like a Tic Tac Toe board. For this example, we will create Boolean Arrays. If you create a 10 by 10 Boolean array, then you essentially create 100 Booleans! This is a MASSIVE way to save time. How do you create a 10 by 10 Array?
It is simple, it it declared just like any other variable, except the size of the Array is enclosed in parentheses next to the variable name.
Dim MyBooleanArray(10, 10) As Boolean

The line above essentially creates 100 Booleans, with 1 line! Well, we know that there are 100 Booleans - but how do we set one part of an array to True?

MyBooleanArray(1, 1) = True

This sets the element (1,1) in MyBooleanArray to True. Simple isn't it? 
MyBooleanArray(1, 1) =
True does not affect any other element in the array. For example, this line does not effect the element (3,3) in MyBooleanArray! That line only affects element (1,1). 

BE CAREFUL: Actually, there are 121 elements when you
Dim MyBooleanArray(10, 10) As Boolean, (0,0) is also considered an element, thus its absolute size is (11,11) <-- you add one because 0,0 is an element. If you wanted an absolute size of (10,10), then you would Dim MyBooleanArray(9, 9) As Boolean, but you do not need to worry about the (0,0) because (unless you are dealing with databases) you can just ignore this - just pretend it is not there. Be careful if you are dealing with databases, and you do not want to use too much memory, or want to allocate only a certain amount of data, or something of the like. For our game, we can just ignore this.

Well, for our game, we want to keep track of all 9 squares in the 3 by 3 Tic Tac Toe board.  Remember the crafty naming conventions from the Basic Block Statements tutorial? We will do something like that for this one! The name for our Boolean will be ClickedSquare(3,3) <-- it is a 3 by 3 array which is called ClickedSquare. 
Declare a 3 by 3 Boolean Array called ClickedSquare in the Declarations area (At the top of your code; the variables created here are also referred to as Global variables)
Dim ClickedSquare(3, 3) As Boolean
 

We can check if an element is True by using the If statement.

If ClickedSquare(1, 1) = False Then
'Set the square to X or O
'Now that it is X or O, we don't want it to be clicked again, so we make it True (see line below)
ClickedSquare(1, 1) = True
End If

 

The code above checks weather the element, (1,1) in the Boolean Array ClickedSquare is True. Look at the comment. We know that when that square hasn't been clicked, you want it to change to X or O. So, we copy and paste that code in between If and End If. For example, this is what sqr1_1.Click should look like:

        If ClickedSquare(1, 1) = False Then
            'Do the code that you want when that square hasn't been clicked.
            If PlayerTurn Mod 2 = 0 Then
                sqr1_1.Image = Image.FromFile("x.jpg")
                PlayerTurn += 1
            ElseIf PlayerTurn Mod 2 = 1 Then
                sqr1_1.Image = Image.FromFile("o.jpg")
                PlayerTurn += 1
            End If 
            'Now that it is X or O, we don't want it to be clicked again, so we make it True 
            ClickedSquare(1, 1) = True
        End If 

There are 2 If Statements "nested" with each other, this is known as a Nested If Statement. The inner If Statement (If PlayerTurn Mod 2 = 0) only executes when the outer If Statement (If ClickedSquare(1, 1) = False) is executed. Visual Basic. NET makes it easy for us to see how it executes by the indenting, which is just a visual aid. 

As you have probably guessed, you are going to take every square's .Click statement, and you are going to change it all. Instead of going back and changing it all, we still have 1 more thing we have to do. We still have to check for the winner! Instead of changing it all, and finding out a way to check for winner, and changing it again, it would be better to plan ahead and then change it!

Here are the possible combinations of checking for winner (marked by the red lines)


Horizontal combinations are:
1) sqr1_3, sqr2_3, and sqr3_3
2) sqr1_2, sqr2_2, and sqr3_2
3) sqr1_1, sqr2_1, and sqr3_1


 Vertical Combinations are: 
1) sqr1_1, sqr1_2, and sqr1_3
2) sqr2_1, sqr2_2, and sqr3_2
3) sqr3_1, sqr3_2, and sqr3_3


 Diagonal Combinations are: 
1) sqr1_3, sqr2_2, and sqr3_1
2) sqr1_1, sqr2_2, and sqr3_3

Well as you can tell, there are 8 combinations. Lets say we want to check the winner for X. The first thing we need to is keep track of what squares are X. We can declare a Boolean for each and every square. For example:
sqr1_1isX
sqr2_2isX
(Don't declare the Booleans yet)
When a square becomes X, then the Boolean for that square is set to True. Every turn, we would check who won. We would do this by obviously using an If statement: (Don't type this code in yet)

      If sqr1_1isX And sqr1_2isX And sqr1_3isX Then
               MessageBox.Show("Player X won because there are 3 X's in the first column")

     
ElseIf sqr2_1isX And sqr2_2isX And sqr2_3isX Then
               MessageBox.Show("Player X won because there are 3 X's in the second column")

     
End If  

Obviously the above is a brief way of checking for the winner - it only covers the first 2 columns, we'll get to that part later. For now, the code is not important, but the concept is.  In a Tic-Tac-Toe game, we would have to check for winner every turn (except for the first 4 turns, but we'll ignore that fact for now :p ). Obviously we need to copy and paste the same "Check-For-Winner" code every time the user clicks a square. Instead of doing all that, we can SHORTEN the amount of code we have to type in by using Subs.

Subs are reusable, which means that you don't have to copy and paste the same code every single time!!!!!

What is a Sub? A Sub is a block of code that executes whenever you call it!

 We have already seen subs

Where? Well take a look at: 
Private Sub sqr3_2_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles sqr3_2.Click)

End Sub

It says Sub !(For now, ignore the stuff in parentheses). This is what a sub is. Let's go back to our brief "Check-For-Winner" code and place it in a sub. Subs are placed after "Windows Form Designer Code and before End Class, just like where the other Subs are placed (like Private Sub 2_2.Click for example) (Don't type this code in yet)

Private Sub CheckForWinnerX()

   If sqr1_1isX And sqr1_2isX And sqr1_3isX Then
               MessageBox.Show("Player X won because there are 3 X's in the first column")
  
ElseIf sqr2_1isX And sqr2_2isX And sqr2_3isX Then
               MessageBox.Show("Player X won because there are 3 X's in the second column")
  
End If  

End Sub

OK, we have a sub... what do we do with it??? Easy - remember that we need to check for winner every time the user clicks a square? (For now, simply ignore the fact that we have to "CheckForWinnerO" <-- later in this tutorial)

Let's use
Private Sub sqr1_1_Click as an example:

Private Sub sqr1_1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles sqr1_1.Click

 If ClickedSquare(1, 1) = False Then
            

           
If PlayerTurn Mod 2 = 0 Then
                sqr1_1.Image = Image.FromFile("x.jpg")
                PlayerTurn += 1
           
ElseIf PlayerTurn Mod 2 = 1 Then
                sqr1_1.Image = Image.FromFile("o.jpg")
                PlayerTurn += 1
           
End If
            

            ClickedSquare(1, 1) =
False
End If 

CheckForWinnerX() 'This line "calls" the Sub, CheckForWinnerX() * 

End Sub


*When you say CheckForWinnerX(), you are "going" to the Sub, CheckForWinnerX(), and executing what's in it. If we did this the long way, we would, instead of saying CheckForWinnerX(), say this: 
   If sqr1_1isX And sqr1_2isX And sqr1_3isX Then
               MessageBox.Show("Player X won because there are 3 X's in the first column")
  
ElseIf sqr2_1isX And sqr2_2isX And sqr2_3isX Then
               MessageBox.Show("Player X won because there are 3 X's in the second column")
  
End If  

 We might say, "OK, well what's the point? You're going to type that anyways".  When you look at the whole picture, you would be copying and pasting that for EACH and EVERY time the user clicked a square.  Using Subs also helps organize things a little bit, instead of staring at the same long code above), we just glance  at the line: CheckForWinnerX()

Great, so we know how to use Subs, but wait! We have to declare NINE variables just for keeping track of whether the square is X. Why not use Boolean Arrays! A nifty name for a Boolean Array like this would be:
ClickedX(3,3)

You usually create your subs at the very bottom, right above End Class. (Well, its really your choice, but that was my recommendation). 

Here's the ENTIRE sub:

Private Sub CheckForWinnerX()

   If ClickedX(1,1) And ClickedX(1,2) And ClickedX(1,3) Then
               MessageBox.Show("Player X won!")
  
ElseIf ClickedX(2,1) And ClickedX(2,2) And ClickedX(2,3) Then
               MessageBox.Show("Player X won!")
  
ElseIf ClickedX(3,1) And ClickedX(3,2) And ClickedX(3,3) Then
               MessageBox.Show("Player X won!")
  
End If  

'Vertical combinations are listed above

   If ClickedX(1,1) And ClickedX(2,1) And ClickedX(3,1) Then
               MessageBox.Show("Player X won!")
  
ElseIf ClickedX(1,2) And ClickedX(2,2) And ClickedX(3,2) Then
               MessageBox.Show("Player X won!")
  
ElseIf ClickedX(1,3) And ClickedX(2,3) And ClickedX(3,3) Then
               MessageBox.Show("Player X won!")
  
End If

'Horizontal combinations are listed above

   If ClickedX(1,3) And ClickedX(2,2) And ClickedX(3,1) Then
               MessageBox.Show("Player X won!")
  
ElseIf ClickedX(1,1) And ClickedX(2,2) And ClickedX(3,3) Then
               MessageBox.Show("Player X won!")
  
End If

'Diagonal combinations are listed above

End Sub

 

Wow! That's our CheckForWinnerX() Sub!! CheckForWinnerO() is basically the same thing! At the Declarations area in your code: (Now you can declare the Boolean Array :D)
Dim
ClickedX(3,3)  As Boolean
Also do this:
Dim
ClickedO(3,3)  As Boolean

Create a Sub called CheckForWinnerO(). Replace all the X's with O's in this sub. Here's the entire Sub:

Private Sub CheckForWinnerO()

   If ClickedO(1, 1) And ClickedO(1, 2) And ClickedO(1, 3) Then
             MessageBox.Show("Player O won!")
   ElseIf ClickedO(2, 1) And ClickedO(2, 2) And ClickedO(2, 3) Then
             MessageBox.Show("Player O won!")
   ElseIf ClickedO(3, 1) And ClickedO(3, 2) And ClickedO(3, 3) Then
             MessageBox.Show("Player O won!")
   End If

'Vertical combinations are listed above

   If ClickedO(1, 1) And ClickedO(2, 1) And ClickedO(3, 1) Then
            MessageBox.Show("Player O won!")
   ElseIf
ClickedO(1, 2) And ClickedO(2, 2) And ClickedO(3, 2)
Then
            MessageBox.Show("Player O won!")
   ElseIf
ClickedO(1, 3) And ClickedO(2, 3) And ClickedO(3, 3)
Then
            MessageBox.Show("Player O won!")
   End
If

'Horizontal combinations are listed above

   If ClickedO(1, 3) And ClickedO(2, 2) And ClickedO(3, 1) Then
      MessageBox.Show("Player O won!")
   ElseIf ClickedO(1, 1) And ClickedO(2, 2) And ClickedO(3, 3) Then
      MessageBox.Show("Player O won!")
   End If

'Diagonal combinations are listed above

End Sub

 
Now, let's go back to a sqr1_1_Click:
(Now you can make changes :D)

Private Sub sqr1_1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles sqr1_1.Click

 If ClickedSquare(1, 1) = False Then
            
           
If PlayerTurn Mod 2 = 0 Then
                sqr1_1.Image = Image.FromFile("x.jpg")
                ClickedX(1,1) =
True
                PlayerTurn += 1
           
ElseIf PlayerTurn Mod 2 = 1 Then
                sqr1_1.Image = Image.FromFile("o.jpg")
                ClickedO(1,1) =
True
                PlayerTurn += 1
           
End If
            
            ClickedSquare(1, 1) =
False
End If 

CheckForWinnerX()
CheckForWinnerO()

End Sub

 Make changes appropriately; in this case, the lines: 
ClickedX(1,1) = True                 *
ClickedO(1,1) = True                 *
CheckForWinnerX()
CheckForWinnerO()
were added on to the sub

*Remember to make changes appropriately to each square. If you were modifying sqr2_2.Click, then you wouldn't say:
ClickedX(1,1) = True   
ClickedO(1,1) = True  

You would use this:
ClickedX(2,2) = True   
ClickedO(2,2) = True  

Programming this game must have been wicked boring, because everything was repetitive. Don't worry about it - the next game will be better...

Cleaning Stuff Up

First of all, run the game. For some of you, there might be a slight problem - the Pictures in the PictureBox are too small for the PictureBoxes. go to the Form Editor, and set each PictureBox's SizeMode to StretchImage. An easy way of doing this is to Ctrl+Click each image and then set its SizeMode property to StretchImage>

Go to the Code Editor(F7), see the minus buttons to the left of each Sub?  Click those
. ... What happened to the code? Nothing.. just click the plus button! Here's an organization tip,  type this in before all the PictureBox's .Click Events:

#Region " .Click Events "

Now hit Enter and it will generate:

#End Region

In between #Region and #End Region, copy and paste all the Square's Click events. Now click the minus button to the left of #Region.... Useful huh? Create another region:

#Region " User Created Subs "

Now hit Enter and it will generate:

#End Region


In between #Region and #End Region, copy and paste the CheckForWinnerX() and CheckForWinnerO() Subs. Now click the minus button to the left of #Region. This is really useful when you've type a TON of code and you ALREADY KNOW what it does, and you don't want it to take too much space, or it takes too long to scroll to the bottom because there's too much repetitive code at the top!

Also - make your PictureBox's the same color if you haven't already done so yet. 

Well, you're done with this game! Have fun with it, see if you can add a Computer player, or add a Reset Board button, or check for a tie, which is pretty simple. 

 

 

 

 

The Source Code for this tutorial is located here:

You can also locate this by logging in to vbProgramming Forums and going to:
Tutorials > Tutorial Source Code > Source Code