Programming Example: Tic-Tac-Toe
This program, which implements the classic game of Tic-Tac-Toe, incorporates the following:
This sample program was originally given as a student exercise, with the specifications as follows:
Write a VB application that will enable a human player to play a classic game of Tic-Tac-Toe against the computer.
The application should begin with a form that contains the following elements:
- A label saying "Welcome to Tic-Tac-Toe"
- Two radio buttons enclosed in a group box. The text for the radio buttons should be "X" and "O". The text for the group box should be "Select 'X' or 'O' and click OK".
- A button with the text "OK".
When the user clicks OK, exit this form and display the main form (the game board).
At the start of each game, the application should select who should go first at random, and display an appropriate message to the user in a message box (either "You go first this time." or "This time, I will go first.")
The game board should be set up with a set of labels (simulating a "control array") named lblSquare0 through lblSquare8. When a player clicks one of the available labels, an "X" or an "O" (depending on the user's initial selection) should appear in that label. Then the computer should make its move.
When the program detects a win, a line should be drawn through the "three in a row". If the player wins, the message "YOU WIN !!!" should flash across the game board; if the computer wins, the message "YOU LOSE!!!" (or "I WIN!!!" or "COMPUTER WINS!!!") should flash across the game board. If the game ends in a tie, the message "IT'S A TIE!!!" should flash across the game board. (Hint: To get the flashing message, use a label in conjunction with a timer and toggle the label's Visible property on and off.)
The program should provide options to play a new game and to quit.
The program should provide keep four counts: games played, games won, games lost, and games tied. These counts should be displayed on the form.
The overall appearance of the application should be tasteful and suggest "fun". Experiment with various colors and fonts until you get it the way you want it.
Your program should implement the following algorithm to try to make the computer win:
(1) Examine the board for a winning move, and if you find one, make that move – otherwise proceed to step (2).
(2) Examine the board to see if your opponent has a winning move, and if so, select that square to block, otherwise proceed to step (3).
(3) If the center square is available, select it, otherwise proceed to step (4).
(4) If you are already occupying the center square, and a side square is available, take the side square, otherwise proceed to step (5).
(5) If a corner square is available, then take it, otherwise, take the next available square.
Note: When the above algorithm is implemented, it is possible for a smart player to beat the computer if the player is able to go first. If you switch steps (4) and (5), it may be impossible for a player to win; the best they can do is tie.
(screenshots of my version of the solution)
Download the solution for this project here.
Getting the "win lines" to appear OVER (on top of) the game board labels was not straightforward. Through trial and error, I was able to get this working by calling the LineShape's BringToFront method, followed by calling the Labels' SendToBack method. And then this will only work if the LineShape is initially not visible, and then set its Visible property to True.
A quick demo program (not available for download) illustrates this:
This is the form at design-time. Note that the LineShape appears behind the labels. (There is no way you will get the LineShape to appear on top of the labels at design-time.)
At run-time, the button executes the code on the right. Note that the LineShape's Visible property is set to False, then set to True. Then the LineShape's BringToFront method is called. Then the SendToBack method for all the Lables is called.
Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
LineShape1.Visible = False
LineShape1.Visible = True
The run-time form is shown on the right:
This demo can be downloaded here.
With the methodology I use to simulate control arrays, I use a function called "GetControlByName", which requires iterating through the Controls collection of the parent control where the control resides:
Private Function GetControlByName(ByVal pobjParent As Control, _
ByVal pstrCtlName As String) _
Dim objCtl As Control
For Each objCtl In pobjParent.Controls
If objCtl.Name = pstrCtlName Then
' if control is not found
However, this does not work for Shapes, as Shapes are technically not considered "controls" by VB. Instead, to find the desired shape, you must iterate through the ShapeContainer1.Shapes collection. The Tic-Tac-Toe program includes the following "GetShapeBy Name" function:
Private Function GetShapeByName(ByVal pstrShapeName As String) _
Dim objShape As PowerPacks.Shape
For Each objShape In Me.ShapeContainer1.Shapes
If objShape.Name = pstrShapeName Then
' if control is not found