Hello everyone. Hope you're doing fine today!
Today we're going to see how to create a Tic Tac Toe game in CLI/C++ using Microsoft Visual Studio 2022!
To start, let's first check if we have Visual Studio 2019.
If you don't, then go to the Visual Studio website.
If you already have Visual Studio installed, skip to Getting started.
Installing Visual Studio 2022
Download the Visual Studio 2022 Community Edition.
After the download has completed, open the installer, and follow the steps.
When it has almost finished, it'll appear a dialog where you can select all the components you want to work with (e.g.: C++ game development, mobile development, Linux/C++ development, etc.).
You can scroll down and see more and more components that you will use. Please note that the more stuff you add the more space the program will require.
Now, choose the Desktop development with .NET and Desktop development with C++.
Next, go to the Individual components sidebar.
Search for CLI, and you'll see various options here:
Choose the one that has a checkmark on it (it may be named a bit differently as I am in the Spanish language).
NOTE: Microsoft might release a new version for it, so don't forget to use the latest one in case it's needed.
Once you got all things set up, click on the Install button and wait while it installs.
Now that we got everything set up, we can start coding!
Getting started
Once you have Visual Studio open, we'll see something like this:
We'll choose up the "Create project" option.
Next, we'll see various options to create our project (templates, empty projects, etc.).
If you search out for "clr", you'll see some options like this:
Choose the one that says "Empty CLR project (.NET Framework).
Next, you'll see something up like this:
Choose a directory where'd you like to have it. Choose the .NET Framework version (I recommend using the latest one in the strip menu).
Choose a name for your project. I recommend using TicTacToe, as in many parts of the code it'll depend on the project's name.
Now click on the "Create" button! Wait while the project creates itself (note that it may take some minutes depending on your PC's hardware).
Coding and making the game
Once you have the project/solution opened, click on "Project", then "Add new item".
Next, it'll appear something up like this:
Click on the one that says "UI", then click on the "Windows Form" option.
Choose a name for the file. I recommend using TicTacToe.h
. Then click on the "Add" button. That's it. You have the Windows Form added. Woo-hoo!
At first, it may display an error. Try to re-open the .h
file.
If that doesn't fix it, close the whole project and the program, and re-open it. In the worst cases, restart your PC.
Configuring the project
To ensure the program runs as excepted, we must tweak a few configurations in our little project.
Next:
After doing that:
Everything should be properly configured now! ๐
In the directory where you saved your project, go to the TicTacToe folder.
You may see various files over there. Open TicTacToe.cpp
and TicTacToe.h
In TicTacToe.cpp
, replace the whole code with this one:
#include "TicTacToe.h"
[System::STAThread]
void main(array <System::String^>^ args) {
System::Windows::Forms::Application::EnableVisualStyles();
System::Windows::Forms::Application::SetCompatibleTextRenderingDefault(false);
TicTacToe::TicTacToe form;
System::Windows::Forms::Application::Run(% form);
}
Depending on your project name, the code above might not work as excepted. For example: if my project name is test_project
, I'd have to change TicTacToe
to test_project
. Depending on the namespace name, I'd have to change it accordingly. If the namespace is named my_namespace
, you shall use
#include "TicTacToe.h"
[System::STAThread]
void main(array <System::String^>^ args) {
System::Windows::Forms::Application::EnableVisualStyles();
System::Windows::Forms::Application::SetCompatibleTextRenderingDefault(false);
test_project::my_namespace form; // Here's where you need to update the names. :)
System::Windows::Forms::Application::Run(% form);
}
Now go into the TicTacToe.h
file.
We'll start building the core of the game. ๐
Replace the code in TicTacToe.h
with this one.
The Gist has the main parts of the code: the buttons, menu strips, labels, etc..
Don't compile the code yet! It'll throw lots of errors.
At the end of the code, you'll see this line has #pragma endregion
in it. Before that, add the following code:
uint16_t turn = 0; // Whether to choose if the X or the O will place.
bool match_ended = false; // If the match has ended or not.
Here, we've just created two variables: one: choose who will place, whether the O or the X; two: has the match ended or not?
We'll now be creating the functionality of the "Start game!" button.
The button is supposed to remove itself and add the other buttons so you can click on them and an "O" or "X" will appear.
After the code #pragma endregion
, add the following code:
private: System::Void button1_Click(System::Object^ sender, System::EventArgs^ e) { // "Start game!" button
this->button1->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 8.25F));
this->button1->Location = System::Drawing::Point(80, 58);
this->button1->Name = L"button1";
this->button1->Size = System::Drawing::Size(0, 0);
this->button1->Text = L"";
/**
* @brief Initialize buttons when clicking "Start game!"
*/
//
// button11 ("Restart game" button)
//
this->button11->Location = System::Drawing::Point(184, 149);
this->button11->Name = L"button11";
this->button11->Size = System::Drawing::Size(88, 31);
this->button11->TabIndex = 9;
this->button11->Text = L"Restart game";
this->button11->UseVisualStyleBackColor = true;
this->button11->Click += gcnew System::EventHandler(this, &TicTacToe::restart_game);
//
// button2
//
this->button2->Location = System::Drawing::Point(80, 50);
this->button2->Name = L"button2";
this->button2->Size = System::Drawing::Size(31, 25);
this->button2->TabIndex = 2;
this->button2->Text = L" ";
this->button2->UseVisualStyleBackColor = true;
this->button2->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button3
//
this->button3->Location = System::Drawing::Point(117, 50);
this->button3->Name = L"button3";
this->button3->Size = System::Drawing::Size(31, 25);
this->button3->TabIndex = 3;
this->button3->Text = L" ";
this->button3->UseVisualStyleBackColor = true;
this->button3->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button4
//
this->button4->Location = System::Drawing::Point(154, 50);
this->button4->Name = L"button4";
this->button4->Size = System::Drawing::Size(31, 25);
this->button4->TabIndex = 4;
this->button4->Text = L" ";
this->button4->UseVisualStyleBackColor = true;
this->button4->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button5
//
this->button5->Location = System::Drawing::Point(80, 81);
this->button5->Name = L"button5";
this->button5->Size = System::Drawing::Size(31, 25);
this->button5->TabIndex = 5;
this->button5->Text = L" ";
this->button5->UseVisualStyleBackColor = true;
this->button5->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button6
//
this->button6->Location = System::Drawing::Point(117, 81);
this->button6->Name = L"button6";
this->button6->Size = System::Drawing::Size(31, 25);
this->button6->TabIndex = 6;
this->button6->Text = L" ";
this->button6->UseVisualStyleBackColor = true;
this->button6->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button7
//
this->button7->Location = System::Drawing::Point(154, 81);
this->button7->Name = L"button7";
this->button7->Size = System::Drawing::Size(31, 25);
this->button7->TabIndex = 7;
this->button7->Text = L" ";
this->button7->UseVisualStyleBackColor = true;
this->button7->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button8
//
this->button8->Location = System::Drawing::Point(80, 112);
this->button8->Name = L"button8";
this->button8->Size = System::Drawing::Size(31, 25);
this->button8->TabIndex = 8;
this->button8->Text = L" ";
this->button8->UseVisualStyleBackColor = true;
this->button8->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button9
//
this->button9->Location = System::Drawing::Point(117, 112);
this->button9->Name = L"button9";
this->button9->Size = System::Drawing::Size(31, 25);
this->button9->TabIndex = 9;
this->button9->Text = L" ";
this->button9->UseVisualStyleBackColor = true;
this->button9->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button10
//
this->button10->Location = System::Drawing::Point(154, 112);
this->button10->Name = L"button10";
this->button10->Size = System::Drawing::Size(31, 25);
this->button10->TabIndex = 10;
this->button10->Text = L" ";
this->button10->UseVisualStyleBackColor = true;
this->button10->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
}
This code should do the following as in the video.
As you can see, immediately when you click the button, it removes itself and adds other buttons. The code above should do that.
Now, this is the greatest part: the code for the buttons to place an "O" or an "X"!
After the latest code you added, add the following code:
private: System::Void button_click(System::Object^ sender, System::EventArgs^ e) { // Buttons to place O and X
Button^ Numbers = safe_cast<Button^>(sender);
if ((match_ended) || (Numbers->Text != " ")) { // Check if string is empty. If so, do not change anything.
return;
}
if (turn == 0) {
Numbers->Text = "O";
Numbers->ForeColor = System::Drawing::Color::FromArgb(static_cast<System::Int32>(static_cast<System::Byte>(0)), static_cast<System::Int32>(static_cast<System::Byte>(0)),
static_cast<System::Int32>(static_cast<System::Byte>(192)));
Numbers->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point,
static_cast<System::Byte>(0)));
turn = 1;
}
else if (turn == 1) {
Numbers->Text = "X";
Numbers->ForeColor = System::Drawing::Color::Red;
Numbers->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point,
static_cast<System::Byte>(0)));
turn = 0;
}
/**
* @brief The system to determine if it's a match or not
* We'll first determine if the O wins. After that, we'll check the X
*/
// // O O O
if ((button2->Text == "O") && (button3->Text == "O") && (button4->Text == "O")) { //
//
match_ended = true;
label2->Text = "The O won the game!";
}
// //
else if ((button5->Text == "O") && (button6->Text == "O") && (button7->Text == "O")) { // O O O
//
match_ended = true;
label2->Text = "The O won the game!";
}
// //
else if ((button8->Text == "O") && (button9->Text == "O") && (button10->Text == "O")) { //
// O O O
match_ended = true;
label2->Text = "The O won the game!";
}
// // O
if ((button2->Text == "O") && (button5->Text == "O") && (button8->Text == "O")) { // O
// O
match_ended = true;
label2->Text = "The O won the game!";
}
// // O
else if ((button3->Text == "O") && (button6->Text == "O") && (button9->Text == "O")) { // O
// O
match_ended = true;
label2->Text = "The O won the game!";
}
// // O
else if ((button4->Text == "O") && (button7->Text == "O") && (button10->Text == "O")) { // O
// O
match_ended = true;
label2->Text = "The O won the game!";
}
// // O
else if ((button2->Text == "O") && (button6->Text == "O") && (button10->Text == "O")) { // O
// O
match_ended = true;
label2->Text = "The O won the game!";
}
// // O
else if ((button4->Text == "O") && (button6->Text == "O") && (button8->Text == "O")) { // O
// O
match_ended = true;
label2->Text = "The O won the game!";
}
/**
* @brief The system to determine
* if it's a match or not (for the X)
* We'll determine if the X wins.
*/
// // X X X
if ((button2->Text == "X") && (button3->Text == "X") && (button4->Text == "X")) { //
//
match_ended = true;
label2->Text = "The X won the game!";
}
// //
else if ((button5->Text == "X") && (button6->Text == "X") && (button7->Text == "X")) { // X X X
//
match_ended = true;
label2->Text = "The X won the game!";
}
// //
else if ((button8->Text == "X") && (button9->Text == "X") && (button10->Text == "X")) { //
// X X X
match_ended = true;
label2->Text = "The X won the game!";
}
// // X
if ((button2->Text == "X") && (button5->Text == "X") && (button8->Text == "X")) { // X
// X
match_ended = true;
label2->Text = "The X won the game!";
}
// // X
else if ((button3->Text == "X") && (button6->Text == "X") && (button9->Text == "X")) { // X
// X
match_ended = true;
label2->Text = "The X won the game!";
}
// // X
else if ((button4->Text == "X") && (button7->Text == "X") && (button10->Text == "X")) { // X
// X
match_ended = true;
label2->Text = "The X won the game!";
}
// // X
else if ((button2->Text == "X") && (button6->Text == "X") && (button10->Text == "X")) { // X
// X
match_ended = true;
label2->Text = "The X won the game!";
}
// // X
else if ((button4->Text == "X") && (button6->Text == "X") && (button8->Text == "X")) { // X
// X
match_ended = true;
label2->Text = "The X won the game!";
}
}
All the code above should do:
- We'll first check if the text is NOT empty. If so, do not change the text.
- This code:
if (turn == 0) {
Numbers->Text = "O";
Numbers->ForeColor = System::Drawing::Color::FromArgb(static_cast<System::Int32>(static_cast<System::Byte>(0)), static_cast<System::Int32>(static_cast<System::Byte>(0)),
static_cast<System::Int32>(static_cast<System::Byte>(192)));
Numbers->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point,
static_cast<System::Byte>(0)));
turn = 1;
}
else if (turn == 1) {
Numbers->Text = "X";
Numbers->ForeColor = System::Drawing::Color::Red;
Numbers->Font = (gcnew System::Drawing::Font(L"Microsoft Sans Serif", 8.25F, System::Drawing::FontStyle::Bold, System::Drawing::GraphicsUnit::Point,
static_cast<System::Byte>(0)));
turn = 0;
}
will first add the "O". It'll make it bold and blue.
It'll then trigger the turn ("X" will now place).
Else, if the turn is for the "X", it'll make it bold and red.
It'll then trigger the turn ("O" will now place). And so on...
- The code:
if ((button2->Text == "O") && (button3->Text == "O") && (button4->Text == "O")) { //
//
match_ended = true;
label2->Text = "The O won the game!";
}
// //
else if ((button5->Text == "O") && (button6->Text == "O") && (button7->Text == "O")) { // O O O
//
match_ended = true;
label2->Text = "The O won the game!";
}
// //
else if ((button8->Text == "O") && (button9->Text == "O") && (button10->Text == "O")) { //
// O O O
match_ended = true;
label2->Text = "The O won the game!";
}
// // O
if ((button2->Text == "O") && (button5->Text == "O") && (button8->Text == "O")) { // O
// O
match_ended = true;
label2->Text = "The O won the game!";
}
// // O
else if ((button3->Text == "O") && (button6->Text == "O") && (button9->Text == "O")) { // O
// O
match_ended = true;
label2->Text = "The O won the game!";
}
// // O
else if ((button4->Text == "O") && (button7->Text == "O") && (button10->Text == "O")) { // O
// O
match_ended = true;
label2->Text = "The O won the game!";
}
// // O
else if ((button2->Text == "O") && (button6->Text == "O") && (button10->Text == "O")) { // O
// O
match_ended = true;
label2->Text = "The O won the game!";
}
// // O
else if ((button4->Text == "O") && (button6->Text == "O") && (button8->Text == "O")) { // O
// O
match_ended = true;
label2->Text = "The O won the game!";
}
will determine who wins and if it's valid or not.
For example, it'll check for the first three buttons. If they all include the same value (all "X" or "O"), there'll be a winner, and you can no longer add more "O"'s or "X"'s.
In the video, you saw there was a "Restart game" button. Let's code it!
After the latest code you added, add the following code:
private: System::Void restart_game(System::Object^ sender, System::EventArgs^ e) {
System::Windows::Forms::DialogResult result = MessageBox::Show(this, "Are you sure you want to end match?", "Restart game", MessageBoxButtons::YesNo, MessageBoxIcon::Exclamation);
if (System::Windows::Forms::DialogResult::No == result)
{
// "No" or "Cancel" button.
}
else
{
// "Yes" button.
match_ended = false; // Match has been restarted, therefore it's not ended.
turn = 0; // Make the O go first.
label2->Text = " "; // Reset winner text to default settings.
//
// button2
//
this->button2->Location = System::Drawing::Point(80, 50);
this->button2->Name = L"button2";
this->button2->Size = System::Drawing::Size(31, 25);
this->button2->TabIndex = 2;
this->button2->Text = L" ";
this->button2->UseVisualStyleBackColor = true;
this->button2->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button3
//
this->button3->Location = System::Drawing::Point(117, 50);
this->button3->Name = L"button3";
this->button3->Size = System::Drawing::Size(31, 25);
this->button3->TabIndex = 3;
this->button3->Text = L" ";
this->button3->UseVisualStyleBackColor = true;
this->button3->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button4
//
this->button4->Location = System::Drawing::Point(154, 50);
this->button4->Name = L"button4";
this->button4->Size = System::Drawing::Size(31, 25);
this->button4->TabIndex = 4;
this->button4->Text = L" ";
this->button4->UseVisualStyleBackColor = true;
this->button4->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button5
//
this->button5->Location = System::Drawing::Point(80, 81);
this->button5->Name = L"button5";
this->button5->Size = System::Drawing::Size(31, 25);
this->button5->TabIndex = 5;
this->button5->Text = L" ";
this->button5->UseVisualStyleBackColor = true;
this->button5->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button6
//
this->button6->Location = System::Drawing::Point(117, 81);
this->button6->Name = L"button6";
this->button6->Size = System::Drawing::Size(31, 25);
this->button6->TabIndex = 6;
this->button6->Text = L" ";
this->button6->UseVisualStyleBackColor = true;
this->button6->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button7
//
this->button7->Location = System::Drawing::Point(154, 81);
this->button7->Name = L"button7";
this->button7->Size = System::Drawing::Size(31, 25);
this->button7->TabIndex = 7;
this->button7->Text = L" ";
this->button7->UseVisualStyleBackColor = true;
this->button7->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button8
//
this->button8->Location = System::Drawing::Point(80, 112);
this->button8->Name = L"button8";
this->button8->Size = System::Drawing::Size(31, 25);
this->button8->TabIndex = 8;
this->button8->Text = L" ";
this->button8->UseVisualStyleBackColor = true;
this->button8->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button9
//
this->button9->Location = System::Drawing::Point(117, 112);
this->button9->Name = L"button9";
this->button9->Size = System::Drawing::Size(31, 25);
this->button9->TabIndex = 9;
this->button9->Text = L" ";
this->button9->UseVisualStyleBackColor = true;
this->button9->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
//
// button10
//
this->button10->Location = System::Drawing::Point(154, 112);
this->button10->Name = L"button10";
this->button10->Size = System::Drawing::Size(31, 25);
this->button10->TabIndex = 10;
this->button10->Text = L" ";
this->button10->UseVisualStyleBackColor = true;
this->button10->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
}
}
The code above should do:
- Check if what option did the user choose ("Yes" or "No").
- If the user chose "yes", set
match_ended
tofalse
. - If the user chose "yes", make the "O" go first.
- If the user chose "yes", reset the winner text to default settings.
If the user chose "no", don't do anything, just remove the message box.
The code:
//
// button2
//
this->button2->Location = System::Drawing::Point(80, 50);
this->button2->Name = L"button2";
this->button2->Size = System::Drawing::Size(31, 25);
this->button2->TabIndex = 2;
this->button2->Text = L" ";
this->button2->UseVisualStyleBackColor = true;
this->button2->Click += gcnew System::EventHandler(this, &TicTacToe::button_click);
...
will remove all text from all the buttons and reset them to their default settings.
Last but not least, we'll add a "Help" menu strip containing an "About" section.
After the code you added, add the following code:
private: System::Void aboutToolStripMenuItem_Click(System::Object^ sender, System::EventArgs^ e) {
MessageBox::Show(this,
"Tic Tac Toe game, v0.1 (initial release)\n"
"Copyright (C) 2020 David Leal (halfpacho@gmail.com)\n"
"\nThis project is licensed under GNU General Public License v3.0\n"
"Visit https://www.gnu.org/licenses/gpl-3.0.en.html for more information about the license.", "About", MessageBoxButtons::OK, MessageBoxIcon::Information);
}
The code above should do:
- Add a message box saying when was it created, who made it, and the license.
You can find up the full source code at GitHub.
Now, to test your code, compile the source code and now let's test it!
After it just compiled, you'll see something like this:
![]()
David Leal@david_leal_7
Finally finished my Tic Tac Toe game in December, 19th.
#Windows #Visualstudio #WindowsForms #64bit #TicTacToe #cpp #coding #gui_coding #GUI #MicrosoftWindows
Would you guys like to play it? Please tell me in the comments! ๐20:05 PM - 11 Jan 2021
Hooray! Now you have your Tic Tac Toe game done!
I hope you liked this tutorial. If you found out any bugs, or if the code didn't work for you, please comment and explain your problems.
Share with your friends, if you liked this like it! ๐
Follow me on my Twitter and on GitHub.
See you around! ๐
Top comments (0)