3
\$\begingroup\$

So I've just started teaching myself C++ a few weeks ago and I've decided to work on an implementation of Tic Tac Toe, using the command line. The program allows a human to play against a bot, which simply selects a random location on the board. I'm requesting a review because I'm not sure about a few things that I've done in the program, including the use of pointers, arrays, random number generator, and the general structure. I'm also not by any means an experienced programmer, hence the request for a general review. I strongly appreciate any advice. Thanks.

#include <iostream>
#include <stdlib.h>
using namespace std;
#define row 3
#define col 3
void printBoard(char board[row][col]);
void setBoard(char board[row][col]);
void getInput(char board[row][col], int *rowInput, int *colInput);
int bot(char board[row][col]);
int game(char board[row][col]);
int checkAvailable(char board[row][col], int rowInput, int colInput);
int checkWinner(char board[row][col]);
int main() {
 char board[row][col];
 game(board);
}
int game(char board[row][col]) {
 int rowInput, colInput;
 setBoard(board);
 printBoard(board);
 // game loop
 while(checkWinner(board) == 0) {
 getInput(board, &rowInput, &colInput);
 printBoard(board);
 if (checkWinner(board) == 1) {cout << "X Wins!\n"; break;}
 
 bot(board);
 printBoard(board);
 if (checkWinner(board) == -1) {cout << "O Wins!\n"; break;}
 }
 return 0;
}
void printBoard(char board[row][col]) {
 // print board
 cout << "\n";
 for (int i = 0; i < row; i++) {
 for (int j = 0; j < col; j++) {
 cout << board[i][j] << " ";
 }
 cout << "\n";
 }
}
void setBoard(char board[row][col]) {
 // reset board
 for (int i = 0; i < row; i++) {
 for (int j = 0; j < col; j++) {
 board[i][j] = '0';
 }
 }
}
int bot(char board[row][col]) {
 // bot playing against human
 int random = rand() % 9;
 int botRow = random/3;
 int botCol = random - botRow * 3;
 if(checkAvailable(board, botRow, botCol) == 1) {
 board[botRow][botCol] = 'O';
 return 0;
 }
 else {
 bot(board);
 return 0;
 }
}
void getInput(char board[row][col], int *rowInput, int *colInput) {
 // get input from user (row and column)
 cout << "Enter row: ";
 cin >> *rowInput;
 (*rowInput)--;
 cout << "Enter column: ";
 cin >> *colInput;
 (*colInput)--;
 if(checkAvailable(board, *rowInput, *colInput) == -1) {
 getInput(board, rowInput, colInput);
 }
 else {
 board[*rowInput][*colInput] = 'X';
 }
}
int checkAvailable(char board[row][col], int rowInput, int colInput) {
 // check if square is available
 if (board[rowInput][colInput] == '0') {return 1;}
 else {return -1;}
 return 0;
}
int checkWinner(char board[row][col]) {
 // check if there has been a winner
 // rows
 for (int i = 0; i < row; i++) {
 if (board[i][0] == 'X' && board[i][1] == 'X' && board[i][2] == 'X') {return 1;}
 if (board[i][0] == 'O' && board[i][1] == 'O' && board[i][2] == 'O') {return -1;}
 }
 // columns
 for (int i = 0; i < row; i++) {
 if (board[0][i] == 'X' && board[1][i] == 'X' && board[2][i] == 'X') {return 1;}
 if (board[0][i] == 'O' && board[1][i] == 'O' && board[2][i] == 'O') {return -1;}
 }
 // diagonals
 if (board[0][0] == 'X' && board[1][1] == 'X' && board[2][2] == 'X') {return 1;}
 if (board[0][0] == 'O' && board[1][1] == 'O' && board[2][2] == 'O') {return -1;}
 if (board[2][0] == 'X' && board[1][1] == 'X' && board[0][2] == 'X') {return 1;}
 if (board[2][0] == 'O' && board[1][1] == 'O' && board[0][2] == 'O') {return -1;}
 return 0;
}
pacmaninbw
26.1k13 gold badges47 silver badges114 bronze badges
asked Jun 23, 2021 at 20:57
\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

General Observations

The Good

No global variables!
Nice consistent indentation.
Good use of functions.

Could be Better

The code looks too much like C and not enough like C++. There is no use of C++ container classes such as std::array or std::vector. This would allow you to use iterators rather than raw pointers.

The bot could be smarter. I would start by taking the center cell if the human didn't take it first.

Avoid using namespace std;

If you are coding professionally you probably should get out of the habit of using the using namespace std; statement. The code will more clearly define where cout and other identifiers are coming from (std::cin, std::cout). As you start using namespaces in your code it is better to identify where each function comes from because there may be function name collisions from different namespaces. The identifiercout you may override within your own classes, and you may override the operator << in your own classes as well. This stack overflow question discusses this in more detail.

Constants in C++

The preferred method for constants in C++ is to use a constexpr variable rather than a #define.

constexpr int row = 3;
constexpr int col = 3;

#define is still used in #if CONSTANT #endif.

Code Organization

Function prototypes are very useful in large programs that contain multiple source files, and that case they will be in header files. In a single file program like this it is better to put the main() function at the bottom of the file and all the functions that get used in the proper order above main(). Keep in mind that every line of code written is another line of code where a bug can crawl into the code.

Always Initialize Variables

In the game() function the variables rowInput and colInput are declared but they are not initialized. C++ does not do default initialization of variables and this can lead to use of undefined variables. Always initialize variables when they are declared. Declare and initialize one variable per line to make the code easier to maintain.

Sᴀᴍ Onᴇᴌᴀ
29.6k16 gold badges45 silver badges203 bronze badges
answered Jun 23, 2021 at 22:10
\$\endgroup\$
1
  • \$\begingroup\$ Taking the centre cell is exactly the wrong thing to do if the only play made so far is in a corner. The human will then take the opposite corner, and then always has the threat of taking a third corner and creating two positions to defend. \$\endgroup\$ Commented Jun 24, 2021 at 7:32

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.