In our latest club meeting, we have finally officially begun operations. In this meeting, we made a simple two player Tic Tac Toe game using C++.
Here is the complete code for the game. A detailed explanation follows.
Source Code
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
| #include <iostream>
#include <cstdio>
#include <string>
using namespace std;
void DisplayBoard(char chBoardArray[])
{
cout << endl;
for (int iii = 0; iii < 9; iii++) {
if (chBoardArray[iii] == '0') {
cout << (iii + 1) << "\t";
} else {
cout << chBoardArray[iii] << "\t";
}
if ((iii + 1) % 3 == 0) {
cout << endl << endl;
}
}
}
int CheckWin(char chBoardArray[])
{
int iWinList[8][3] = { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }, { 0, 3, 6 },
{ 1, 4, 7 }, { 2, 5, 8 }, { 0, 4, 8 }, { 2, 4, 6 } };
int iCountX;
int iCountO;
for (int iii = 0; iii < 8; iii++) {
iCountX = 0;
iCountO = 0;
for (int jjj = 0; jjj < 3; jjj++) {
if (chBoardArray[iWinList[iii][jjj]] == 'X') {
iCountX++;
} else if (chBoardArray[iWinList[iii][jjj]] == 'O') {
iCountO++;
}
}
if (iCountX == 3) {
return 1;
}
if (iCountO == 3) {
return 2;
}
}
return 0;
}
int main()
{
cout << "Player 1, enter your name: ";
string strPlayer1;
getline(cin, strPlayer1);
cout << "Player 2, enter your name: ";
string strPlayer2;
getline(cin, strPlayer2);
char chBoardArray[10] = "000000000";
string strWinner;
int iWin;
for (int iii = 0; iii < 9; iii++) {
DisplayBoard(chBoardArray);
if (iii % 2 == 0) {
cout << strPlayer1 << ", enter position to set X: ";
} else {
cout << strPlayer2 << ", enter position to set O: ";
}
int iPosition;
cin >> iPosition;
cin.ignore();
if (iPosition > 9 || iPosition < 1) {
cout << "Enter a valid position." << endl;
--iii;
continue;
}
if (chBoardArray[iPosition - 1] != '0') {
cout << "Oops! That position is already taken." << endl;
--iii;
continue;
}
if (iii % 2 == 0) {
chBoardArray[iPosition - 1] = 'X';
} else {
chBoardArray[iPosition - 1] = 'O';
}
iWin = CheckWin(chBoardArray);
if (iWin == 1) {
strWinner = strPlayer1;
break;
} else if (iWin == 2) {
strWinner = strPlayer2;
break;
}
}
DisplayBoard(chBoardArray);
if (iWin == 0) {
cout << "Draw Game." << endl;
} else {
cout << strWinner << " wins!" << endl;
}
return 0;
}
|
Explanation
1
2
3
4
5
| #include <iostream>
#include <cstdio>
#include <string>
using namespace std;
|
Three header files are included in this program, iostream for cin and cout, cstdio for fgets() and string for strlen(). The standard namespace has also been used for easy access to cin and cout.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
| void DisplayBoard(char chBoardArray[])
{
cout << endl;
for (int iii = 0; iii < 9; iii++) {
if (chBoardArray[iii] == '0') {
cout << (iii + 1) << "\t";
} else {
cout << chBoardArray[iii] << "\t";
}
if ((iii + 1) % 3 == 0) {
cout << endl << endl;
}
}
}
|
DisplayBoard() is a function which is used to display the array which contains the information of the game board in a 3 X 3 matrix. For every three lines, a newline is printed. If the array contains the character zero, the index of the array plus one (because we want to convert one based indices, not zero based) is printed. Otherwise, the character present on that index is printed.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| int CheckWin(char chBoardArray[])
{
int iWinList[8][3] = { { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 }, { 0, 3, 6 },
{ 1, 4, 7 }, { 2, 5, 8 }, { 0, 4, 8 }, { 2, 4, 6 } };
int iCountX;
int iCountO;
for (int iii = 0; iii < 8; iii++) {
iCountX = 0;
iCountO = 0;
for (int jjj = 0; jjj < 3; jjj++) {
if (chBoardArray[iWinList[iii][jjj]] == 'X') {
iCountX++;
} else if (chBoardArray[iWinList[iii][jjj]] == 'O') {
iCountO++;
}
}
if (iCountX == 3) {
return 1;
}
if (iCountO == 3) {
return 2;
}
}
return 0;
}
|
CheckWin() checks whether a player has won or not. It returns 1 if player 1 wins, 2 if player 2 wins, and 3 if the game has not yet determined a winner. For this, the iWinList 2D array stores all possible winning combinations. Then, all combinations are checked, and if they contain an X or an O at the appropriate places, it returns a number depending on which player one. If no player wins control reaches the end of both loops and 0 is returned.
1
2
3
4
5
6
7
8
9
| int main()
{
cout << "Player 1, enter your name: ";
string strPlayer1;
getline(cin, strPlayer1);
cout << "Player 2, enter your name: ";
string strPlayer2;
getline(cin, strPlayer2);
|
The main() function is where execution begins. First of all, the names of the two players are taken and stored in variables. These variables aren't simple C style strings, but are instances of std::string. This is a class used to work with and manipulate strings in C++.
1
2
3
| char chBoardArray[10] = "000000000";
string strWinner;
int iWin;
|
A character array is declared and initialized with zeroes. Since it is a string, this can be done easily in one line. strWinner is declared to hold the name of the winning player, and iWin is used to determine the state of the game, whether a player has won or not.
1
| for (int iii = 0; iii < 9; iii++) {
|
The rest of the code is placed in a for loop which will run five times, because that is the maximum number of turns that will be played.
1
2
3
4
5
6
7
| DisplayBoard(chBoardArray);
if (iii % 2 == 0) {
cout << strPlayer1 << ", enter position to set X: ";
} else {
cout << strPlayer2 << ", enter position to set O: ";
}
|
The board is displayed, and the the appropriate player is asked to enter the position to set either X or O.
1
2
3
| int iPosition;
cin >> iPosition;
cin.ignore();
|
The position is accepted from the user and stored in a variable. The cin object does not read the newline character and it stays in the input stream. To avoid any future conflict, cin.ignore() has been used right after cin to remove the newline character from the stream and clear it.
1
2
3
4
5
6
7
8
9
10
11
| if (iPosition > 9 || iPosition < 1) {
cout << "Enter a valid position." << endl;
--iii;
continue;
}
if (chBoardArray[iPosition - 1] != '0') {
cout << "Oops! That position is already taken." << endl;
--iii;
continue;
}
|
If the position is not a valid index or there is already an X or O at that position, another iteration of the loop is forced. To make sure that in the next iteration the value of the loop variable remains the same, it is decremented, as it will be incremented again by the loop.
1
2
3
4
5
| if (iii % 2 == 0) {
chBoardArray[iPosition - 1] = 'X';
} else {
chBoardArray[iPosition - 1] = 'O';
}
|
Depending whether it is player one's turn or player two's turn, an X or O is set at the position entered by the user.
1
2
3
4
5
6
7
8
9
| iWin = CheckWin(chBoardArray);
if (iWin == 1) {
strWinner = strPlayer1;
break;
} else if (iWin == 2) {
strWinner = strPlayer2;
break;
}
}
|
CheckWin() is called, and the return value is stored in iWin. If there is a winner, strWinner is updated and the loop is exited.
1
2
3
4
5
6
7
8
9
10
| DisplayBoard(chBoardArray);
if (iWin == 0) {
cout << "Draw Game." << endl;
} else {
cout << strWinner << " wins!" << endl;
}
return 0;
}
|
The final board is displayed, and the name of the player if declared if there is a winner, or draw otherwise.