Command Line TicTacToe

I recently completed a command line tictactoe, and was wondering what I could change to make it better, besides making it object orientated which I am just starting to work on. I realize that some of the programming logic is badly done, which is why I'm asking for opinions :) Any help is greatly appreciated.
Here is the 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
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
#include <iostream>
using namespace std;

void ClearBoard();
void PrintBoard();
void Info();
void PlacePiece(int col, int row);
void GetInput();
void CheckWin();
//Board to help with calculations
int IBoard[3][3] = {0};
//Board to display characters
char Board[3][3];
int turn = 1;
int PieceValue = 0;
bool Play = true;

int main(int argc, const char * argv[])
{
    Info();
    ClearBoard();
    PrintBoard();
    int Command = 0;
    cin >> Command;
    if (Command == 2)
        Play = false;
    int BoardFull = 0;
    while (Play) {
        GetInput();
        CheckWin();
        BoardFull++;
        //Check Cats Game
        if (BoardFull == 9) {
            cout << "Cats Game" << endl;
            Play = false;
        }
    }

    return 0;
}

void ClearBoard() {
    for (int i = 0; i < 3; i++)
		for (int j=0; j < 3; j++)
			Board[i][j] = '-';
}

void PrintBoard () {
    cout << "\t1 \t2 \t3 " << endl;
    cout << "1\t" << Board[0][0] << "  \t" << Board[1][0] << "  \t" << Board[2][0] << endl;
    cout << "2\t" << Board[0][1] << "  \t" << Board[1][1] << "  \t" << Board[2][1] << endl;
    cout << "3\t" << Board[0][2] << "  \t" << Board[1][2] << "  \t" << Board[2][2] << endl;
    
    /* for (int i=0; i < 3; i ++)
	{
		for (int j=0; j < 3; j++)
		{
			cout << Board[j][i] << "\t";
			if (j < 2)
				cout << "|\t";
		}
		if (i < 2)
			cout << "\n------------------\n";
	} */
    cout << endl << endl;
}

void Info() {
    cout << "Commands: \n1.Place piece\n2.Exit" << endl;
}

void PlacePiece(int row, int col) {
    //Check turn to change value of piece
    char piece;
    if (turn % 2 == 0) {
        piece = 'O';
    }
    else {
        piece = 'X';
    }
    Board[row][col] = piece;
    
    //Place a value of 1 or -1 into a seperate array to allow for easier win calculations
    
    if (piece == 'O') {
        PieceValue = -1;
    }
    else if (piece == 'X') {
        PieceValue = 1;
    }
    IBoard[row][col]  = PieceValue;
    
    turn++;
    
    PrintBoard();
}

void GetInput() {
    //Check Turn
    if (turn % 2 == 0)
        cout << "Player 2, its your turn." << endl;
    else
        cout << "Player 1, its your turn." << endl;
    
    cout << "Please select a location (ROW COL): " << endl;
    int row = 0, col = 0;
    cin >> row >> col;
    //Check to see if input is valid
    if (row > 3 || row < 1 || col > 3 || col < 1) {
        cout << "Invalid range, try again." << endl;
        cin >> row >> col;
    }
    if (IBoard[col - 1][row - 1] != 0) {
        cout << "Spot taken, try again." << endl;
        cin >> row >> col;
    }
    PlacePiece(col - 1, row - 1);  //Since arrays are 0 indexed base, have to cahnge 
}

void CheckWin() {
    bool WinX = false;
    bool WinO = false;
    //Check Horizontal Win
    for (int i = 0; i < 3; i++) {
        int TotalValue = 0;
        for (int j = 0; j < 3; j++) {
            TotalValue += IBoard[i][j];
        }
        if (TotalValue == 3) {
            WinX = true;
        }
        else if (TotalValue == -3) {
            WinO = true;
        }
    }
    //Check Verical Win
    for (int j = 0; j < 3; j++) {
        int TotalValue = 0;
        for (int i = 0; i < 3; i++) {
            TotalValue += IBoard[i][j];
        }
        if (TotalValue == 3) {
            WinX = true;
        }
        else if (TotalValue == -3) {
            WinO = true;
        }
    }
    //Check Diagonal Win
    int TotalValue = 0;
    TotalValue = IBoard[0][0] + IBoard[1][1] + IBoard[2][2];
    if (TotalValue == 3) {
        WinX = true;
    }
    else if (TotalValue == -3) {
        WinO = true;
    }
    TotalValue = IBoard[0][2] + IBoard[1][1] + IBoard[2][0];
    if (TotalValue == 3) {
        WinX = true;
    }
    else if (TotalValue == -3) {
        WinO = true;
    }
    //End Game if Won
    if (WinX) {
        cout << "Player 1 Wins";
        Play = false;
    }
    if (WinO)  {
        cout << "Player 2 Wins";
        Play = false;
    }
}

Here is a sample output:
Commands: 
1.Place piece
2.Exit
	1 	2 	3 
1	-  	-  	-
2	-  	-  	-
3	-  	-  	-


1
Player 1, its your turn.
Please select a location (ROW COL): 
2 2
	1 	2 	3 
1	-  	-  	-
2	-  	X  	-
3	-  	-  	-


Player 2, its your turn.
Please select a location (ROW COL): 
1 1
	1 	2 	3 
1	O  	-  	-
2	-  	X  	-
3	-  	-  	-


Player 1, its your turn.
Please select a location (ROW COL): 

3 2
	1 	2 	3 
1	O  	-  	-
2	-  	X  	-
3	-  	X  	-


Player 2, its your turn.
Please select a location (ROW COL): 
3 3
	1 	2 	3 
1	O  	-  	-
2	-  	X  	-
3	-  	X  	O


Player 1, its your turn.
Please select a location (ROW COL): 
1 2
	1 	2 	3 
1	O  	X  	-
2	-  	X  	-
3	-  	X  	O


Player 1 Wins
I realize that some of the programming logic is badly done


I would say it's pretty good. What parts are you unhappy with?

I think you can go without int IBoard[3][3], but not exactly sure. For example:
1
2
3
4
5
6
7
8
9
10
11
12
13
   //Check Horizontal Win
    for (int i = 0; i < 3; i++) {
        int TotalValue = 0;
        for (int j = 0; j < 3; j++) {
            TotalValue += Board[i][j];  // This is just Board[3][3]
        }
        if (TotalValue == 3 * 'X') {
            WinX = true;
        }
        else if (TotalValue == 3 * 'O') {
            WinO = true;
        }
    }


You could also try making checkWin() return bool, and have this be the condition of the while loop. The game must be over if the total of the Board is (5 * 'X') + (4 * 'O') as well, so checkWin() can also handle the case of a cat's game.
Last edited on
Thanks for the reply.
One part I would say I'm not pleased with is how it decides what piece to place. Would it be better to store the players piece with the player itself? but then it would be object orrentated.

Also what do you mean about not needing the IBoard array, wouldn't
TotalValue += Board[i][j];
cause an error? as Board[3][3] is a char array.

I do agree that the CheckWin() should handle the full board scenario.

One last thing, off topic. Are there any other little 'mini games' I can make. As I want more practice, but I find it more fun to create games, applying what I learn, rather then just doing examples I can't really think of a scenario to use. So far I've made: Number Guessing(Both Player and Computer Guesses), RockPaperScissors, and TicTacToe.
Instead of having the user input the row and col you could have the board start out with numbers and fill in the X's and O's based on input. I think it would be easier to play, just a matter of taste though :)

1
2
3
4
5
6
 
1       2       3

4       5       6
 
7       8       9


For example, if the user entered 5:

1
2
3
4
5
6
 
1       2       3

4       X       6
 
7       8       9
Thanks for replying. I actually did think about doing it that way at first, but never ended up doing it. But it is a good idea for making it more usable, thanks!
Topic archived. No new replies allowed.