Hello,
In this tutorial I will try to explain how to make a very good Tic Tac Toe game.
For the purpose of maximizing the compatibility we will write the game in .NET Framework 2 (But any other version will also do as well)
If you're not familiar to the rules of tic tac toe look HERE (Wikipedia)
1. Open your IDE and make a new project, call it Tic Tac Toe (If you want)
2. Open the project properties tab, go to the resources
3. Add these images for X and O (Download Images Here), of course you can put any image you want there...
OK we have our project prepared, now's the time for the real stuff...
Before we start to code we will just think through the process of creating this game:
Let's think of what will our game need to have:
1. It will need to have 9 buttons for fields (where would you play if it hasn't them?
2. It will need to have a button to start a new game
3. It will need to have a close button
4. It will need to have two radio Buttons to select if you want the single Player or the multi Player mode (optional)
5. It can have a menu strip with the new game and exit menu item.
Before you put these controls in the designer let's think a bit more...
How are we going to realize the public interface?
1. Well for starters we will need to have a resize method so that our controls stay accordingly positioned always
2. We will need to have a reset method so that we can start a new game
3. We will need to have a check method to see If anyone has won
4. We will need to have some computer logic for the AI
5. We also need to have some logic what happens when a button is clicked
So that wraps up our planing of the game
Enough with the 'foreplay' time to do some code
Not that fast actually...
First put down your design, I suggest you put the buttons like this so that we don't get any misunderstanding problems

And then I added all of the controls we discussed so I got a window layout like this

So now we finally get to actually coding something...
Declarations
This one is short...
We will add two images, one X and one O, we will use the images from the resources (if you added it at the start)
AND we will add a player Turn indicator for the multi player mode so that the AI knows then to put X and when O
//Declaring the variables in the project
//The turn indicator, for multi player mode
private bool player Turn = false;
//The images for x and o
private Image x = Properties.Resources.X;
private Image o = Properties.Resources.O;
Resize Method
We will start with the resize method:
So we need to set the button width, we will set it to the (client rectangle width - radio buttons width) / 3 (it looks nice that way)
//Declare and initialize a local variable, the default button width
int defaultWidth = (this.ClientRectangle.Width - radioButton1.Width) / 3;
//Set the buttons width to the default one
button1.Width = button2.Width = button3.Width = button4.Width = button5.Width = button6.Width = button7.Width = button8.Width = button9.Width = defaultWidth;
Next we set the height, I set this one to the (client rectangle height - menu strip height) / 3 (again it looks nice that way)
//Declare and initialize a local variable, the default button height
int defaultHeight = (this.ClientRectangle.Height - menuStrip1.Height) / 3;
//Set the buttons height to the default one
button1.Height = button2.Height = button3.Height = button4.Height = button5.Height = button6.Height = button7.Height = button8.Height = button9.Height = defaultHeight;
Next we need to left align the buttons, a thing to notice is that there are 3 columns and the buttons of a same column have the same left distances
//Declare the two positions for the two columns
int secondColumn = button1.Width;
int thirdColumn = 2 * button1.Width;
//Position the buttons to the according column
button1.Left = button4.Left = button7.Left = 0;
button2.Left = button5.Left = button8.Left = secondColumn;
button3.Left = button6.Left = button9.Left = thirdColumn;
Notice there isn't any first row, that's because it's left distance is 0
Now we top align the buttons, a thing to notice is that there are 3 rows
//Declare the three positions for the two rows
int firstRow = menuStrip1.Height;
int secondRow = menuStrip1.Height + button1.Height;
int thirdRow = menuStrip1.Height + 2 * button1.Height;
//Position the buttons to the according row
button1.Top = button2.Top = button3.Top = firstRow;
button4.Top = button5.Top = button6.Top = secondRow;
button7.Top = button8.Top = button9.Top = thirdRow;
Now we position the radio buttons
//Positions the left anchor of the radio buttons
radioButton1.Left = button1.Left + button1.Width + 5;
radioButton2.Left = radioButton1.Left;
//Positions the top anchor of the radio buttons
radioButton1.Top = button1.Top;
radioButton2.Top = radioButton1.Top + radioButton1.Height + 10;
I trust you understand how this is aligned...
Now we just need to align the two remaining buttons (new game and exit)
//Positions the left anchor of the buttons
button10.Left = button11.Left = radioButton1.Left;
//Positions the top anchor of the buttons
button10.Top = radioButton2.Top + radioButton2.Height + 10;
button11.Top = button10.Top + button10.Height + 10;
So my resize method looks like this:
Spoiler
Notice that it's void since it doesn't return any value, and that it's private since it is to be called from the same class
If you build and run your program, you'll see that nothing happens
That's because we haven't called the method anywhere...
I called the method in the Form1_Load and Form1_Resize events
Now when you build and run your program you'll see that it's always nicely positioned and sized no matter what you do to the form...
Reset Method
Now for the reset method:
We need to make all of the buttons background images to nothing (that is to remove the background images)
We also need to make sure that the player 2 turn is not active
private void _Reset()
{
//This resets the game (Initializes a new game)
button1.BackgroundImage = null;
button2.BackgroundImage = null;
button3.BackgroundImage = null;
button4.BackgroundImage = null;
button5.BackgroundImage = null;
button6.BackgroundImage = null;
button7.BackgroundImage = null;
button8.BackgroundImage = null;
button9.BackgroundImage = null;
playerTurn = false;
}
This was my reset method
Check Method
This one is rather long and I will explain only a part of it and the logic behind it, I trust you can figure out the rest (If not I will include the method at the end of this paragraph)
So this time I will firstly put code and explain it
if (button3.BackgroundImage == x)
{
if (button5.BackgroundImage == x)
{
if (button7.BackgroundImage == x)
{
//Show the message to tell who has won
MessageBox.Show("X has won!");
return;
}
}
}
This is a nested if statement, so we check if button 3 has been clicked by the player (X) then if the button5 and finally if button7 is clicked, if this is all true then X has won and then a MessageBox should be showed
Logic:
We will check for every combination if X has won and also for O...
If buttons 1, 2 and 3
If buttons 1, 4, and 7
....
And the same for O
Here's the full method
Spoiler
Computer Logic
There are two ways to do this: the 'stupid' way and the 'half-smart' way (or the 'half-stupid' choose your favorite)...
The stupid way would be to program every possible move and the response to it
It is rather long and tedious and there is no gain, so I won't explain it here
The 'half-smart' way is to actually put some logic
So the computer priorities should be:
1. Play a move that can win (If that isn't possible -->)
2. Play a move that stops your opponent from winning (If that isn't possible -->)
3. Play any move
This shortens the actual amount of work but there is still a considerable amount of work to do
I won't explain everything just a few examples, the rest is up to you (I will still post the whole method bellow)
if (button1.BackgroundImage == o && button2.BackgroundImage == o)
{
if (button3.BackgroundImage == null)
{
button3.BackgroundImage = o;
_Check();
return;
}
}
This is an example of the wining move
So if the buttons 1 and 2 are already pressed by the AI and button 3 isn't the press it...
The check to see if someone has one (And the computer has...)
if (button1.BackgroundImage == x && button2.BackgroundImage == x)
{
if (button3.BackgroundImage == null)
{
button3.BackgroundImage = o;
_Check();
return;
}
}
This is an example of the defending move
Again if buttons 1 and 2 are already pressed then press button 3 to prevent the computer from winning
Check to see if anyone has won (And no one has) then return to the selection of moves
if (button1.BackgroundImage == null)
{
button1.BackgroundImage = o;
_Check();
return;
}
This is an example of just playing any button.
If button 1 isn't taken then press it
Check to see if there are any winners if not then return to the move selection
Button Click Logic
The last remaining thing to do is to add the behind the curtains logic in the buttons
So here also I will first add the method and then explain it...
private void _Buttonclick(ref Button theButton)
{
//This is the button happenings
if (radioButton1.Checked)
{
if (theButton.BackgroundImage == null)
{
//Sets the background image of the button to x
theButton.BackgroundImage = x;
//Checks to see if the match is over
_Check();
//Lets the computer play
_ComputerPlay();
}
else
MessageBox.Show("The wanted button is already chosen!");
}
else if (radioButton2.Checked)
{
if (theButton.BackgroundImage == null)
{
if (playerTurn == false)
{
theButton.BackgroundImage = x;
playerTurn = true;
_Check();
}
else
{
theButton.BackgroundImage = o;
playerTurn = false;
_Check();
}
}
else
{
//Shows a message to tell that the button is already chosen
MessageBox.Show("The wanted button is already chosen!");
}
}
else
{
//Shows a message to tell the player that it has first to select a game mode
MessageBox.Show("Please chose a mode of play first...");
}
}
So just a thing to notic is the ref keyword, that tells the compiler to REFERENCE the button and NOT COPY IT INTO A BUFFER so that any changes that happen in the method parameter happen in the referenced button
If the single player mode is selected and if the button that you are clicking is not taken then mark that button and check to see if anyone has won if not the let the computer play, and if the button is taken then tell the user that...
And if the multi player mode is selected the in accordance to the player turn mark the button X or O then check to see if anyone has won, if the button is taken tell that to the user
And if no radiobutton is slected tell the user to select a game mode
Note: The given computer logic makes him unbeatable so that we don't need to make the check return a bool indicating if anyone has won, since the player can't win. The checking if X has one is there just for the multi player mode!
You should implement the button logic in every button click event like this
this._Buttonclick(ref button1); // If it's button one event
Do this for all nine buttons
Accesories
Call this method on the exit button and the exit toolstrip menu item
Close();
Call this method in the new game button adn toolstrip menu item
_Reset();
You could also add the ability for the user to play using the keyboard like this
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
//Gets the key that was pressed and presses the corresponding button
switch (e.KeyData)
{
case Keys.NumPad1:
button7.PerformClick();
break;
case Keys.NumPad2:
button8.PerformClick();
break;
case Keys.NumPad3:
button9.PerformClick();
break;
case Keys.NumPad4:
button4.PerformClick();
break;
case Keys.NumPad5:
button5.PerformClick();
break;
case Keys.NumPad6:
button6.PerformClick();
break;
case Keys.NumPad7:
button1.PerformClick();
break;
case Keys.NumPad8:
button2.PerformClick();
break;
case Keys.NumPad9:
button3.PerformClick();
break;
case Keys.Divide:
button10.PerformClick();
break;
case Keys.Multiply:
if (radioButton1.Checked == false && radioButton2.Checked == false)
radioButton1.PerformClick();
else if (radioButton1.Checked)
radioButton2.PerformClick();
else if (radioButton2.Checked)
radioButton1.PerformClick();
break;
}
}
If you're adding this make sure that the KeyPreview property of the form is on true!!!
The switch statement takes a value and compares it to it's cases, if nothing is true the do nothing...
We are doing this in the Form1_KeyDown event so that we can check the key pressed by using e.KeyData
This more or less expains itself, no need to reinvent the wheel
And there you go we made a feature rich Tic Tac Toe game
If you need some more help or you need the source I uploaded it here and you can see the project at my GitHub Repo.
PM me or post if you have more questions.
Attached File(s)
-
TicTacToe.zip (1.34MB)
Number of downloads: 1511





MultiQuote







|