|
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
|
|