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:
#include <iostream>
usingnamespace 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, constchar * 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;
}
elseif (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;
}
elseif (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;
}
elseif (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;
}
elseif (TotalValue == -3) {
WinO = true;
}
TotalValue = IBoard[0][2] + IBoard[1][1] + IBoard[2][0];
if (TotalValue == 3) {
WinX = true;
}
elseif (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;
}
elseif (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.
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 :)
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!