I recently began learning C++ and would appreciate your review of this simple tic-tac-toe game I made. I know the "3-in-a-row algorithm" is inefficient, but in what other ways could I improve the code? Thanks for the help!
#include <iostream>
#include <cstdlib>
#include <time.h>
#include <string>
std::string endText;
bool gameOver = false;
int w = 18;
int h = 18;
char numbers[3][3] = { {'1', '2', '3'}, {'4', '5', '6'}, {'7', '8', '9'} };
void drawBoard() {
system("cls");
for (int i = 1; i < w; i++) {
for (int j = 1; j < h; j++) {
if (i % (h / 3) == 0) {
std::cout << "# ";
}
else if (j % (w / 3) == 0) {
std::cout << "# ";
}
else if (i % 3 == 0 && j % 3 == 0) {
int column = ((j / 3) - 1) / 2;
int row = ((i / 3) - 1) / 2;
std::cout << numbers[row][column] << " ";
}
else {
std::cout << " ";
}
}
std::cout << std::endl;
}
std::cout << std::endl;
}
void playerInput() {
int numInput;
bool numFound = false;
std::cout << "Select a box to mark: ";
std::cin >> numInput;
while (std::cin.fail()) {
drawBoard();
std::cin.clear();
std::cin.ignore();
std::cout << "Invalid input." << std::endl << std::endl;
std::cout << "Select a box to mark: ";
std::cin >> numInput;
}
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
int charInt = numbers[i][j] - '0';
if (numInput == charInt) {
numbers[i][j] = 'X';
drawBoard();
numFound = true;
break;
}
else if (j == 2 && i == 2) {
std::cout << "Invalid input." << std::endl << std::endl;
playerInput();
}
}
if (numFound) {
break;
}
}
}
void compRandInput() {
int row = rand() % 3;
int column = rand() % 3;
if (numbers[row][column] != 'X' && numbers[row][column] != 'O') {
numbers[row][column] = 'O';
}
else {
compRandInput();
}
}
void checkRow(bool & madeTurn, char check) {
for (int i = 0; i < 3; i++) {
int symbolCount = 0;
int columnNumber = -1;
for (int j = 0; j < 3; j++) {
if (numbers[i][j] == check) {
symbolCount++;
}
else if (numbers[i][j] != 'X' && numbers[i][j] != 'O') {
columnNumber = j;
}
}
if (symbolCount == 2 && columnNumber >= 0) {
numbers[i][columnNumber] = 'O';
madeTurn = true;
break;
}
}
}
void checkColumn(bool & madeTurn, char check) {
for (int j = 0; j < 3; j++) {
int symbolCount = 0;
int rowNumber = -1;
for (int i = 0; i < 3; i++) {
if (numbers[i][j] == check) {
symbolCount++;
}
else if (numbers[i][j] != 'X' && numbers[i][j] != 'O') {
rowNumber = i;
}
}
if (symbolCount == 2 && rowNumber >= 0) {
numbers[rowNumber][j] = 'O';
madeTurn = true;
break;
}
}
}
//Diagonal from top left to bottom right
void checkTwoInDiagonalsB(bool & madeTurn, char check, char place) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (numbers[i][j] == check) {
if (j == 0 && i == 0) {
if (numbers[i + 1][j + 1] == check && numbers[i + 2][j + 2] != 'O' && numbers[i + 2][j + 2] != 'X') {
numbers[i + 2][j + 2] = place;
madeTurn = true;
break;
}
else if (numbers[i + 2][j + 2] == check && numbers[i + 1][j + 1] != 'O' && numbers[i + 1][j + 1] != 'X') {
numbers[i + 1][j + 1] = place;
madeTurn = true;
break;
}
}
else if (j == 1 && i == 1) {
if (numbers[i - 1][j - 1] == check && numbers[i + 1][j + 1] != 'O' && numbers[i + 1][j + 1] != 'X') {
numbers[i + 1][j + 1] = place;
madeTurn = true;
break;
}
else if (numbers[i + 1][j + 1] == check && numbers[i - 1][j - 1] != 'O' && numbers[i - 1][j - 1] != 'X') {
numbers[i - 1][j - 1] = place;
madeTurn = true;
break;
}
}
else if (j == 2 && i == 2) {
if (numbers[i - 2][j - 2] == check && numbers[i - 1][j - 1] != 'O' && numbers[i - 1][j - 1] != 'X') {
numbers[i - 1][j - 1] = place;
madeTurn = true;
break;
}
else if (numbers[i - 1][j - 1] == check && numbers[i - 2][j - 2] != 'O' && numbers[i - 2][j - 2] != 'X') {
numbers[i - 2][j - 2] = place;
madeTurn = true;
break;
}
}
}
}
if (madeTurn) {
break;
}
}
}
//Diagonal from top right to bottom left
void checkTwoInDiagonalsF(bool & madeTurn, char check, char place) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (numbers[i][j] == check) {
if (j == 2 && i == 0) {
if (numbers[i + 1][j - 1] == check && numbers[i + 2][j - 2] != 'O' && numbers[i + 2][j - 2] != 'X') {
numbers[i + 2][j - 2] = place;
madeTurn = true;
break;
}
else if (numbers[i + 2][j - 2] == check && numbers[i + 1][j - 1] != 'O' && numbers[i + 1][j - 1] != 'X') {
numbers[i + 1][j - 1] = place;
madeTurn = true;
break;
}
}
else if (j == 1 && i == 1) {
if (numbers[i - 1][j + 1] == check && numbers[i + 1][j - 1] != 'O' && numbers[i + 1][j - 1] != 'X') {
numbers[i + 1][j - 1] = place;
madeTurn = true;
break;
}
else if (numbers[i + 1][j - 1] == check && numbers[i - 1][j + 1] != 'O' && numbers[i - 1][j + 1] != 'X') {
numbers[i - 1][j + 1] = place;
madeTurn = true;
break;
}
}
else if (j == 0 && i == 2) {
if (numbers[i - 2][j + 2] == check && numbers[i - 1][j + 1] != 'O' && numbers[i - 1][j + 1] != 'X') {
numbers[i - 1][j + 1] = place;
madeTurn = true;
break;
}
else if (numbers[i - 1][j + 1] == check && numbers[i - 2][j + 2] != 'O' && numbers[i - 2][j + 2] != 'X') {
numbers[i - 2][j + 2] = place;
madeTurn = true;
break;
}
}
}
}
if (madeTurn) {
break;
}
}
}
void compInput() {
bool turnMade = false;
//Computer checks if it can make 3 in a row
checkColumn(turnMade, 'O');
if (!turnMade) {
checkRow(turnMade, 'O');
}
if (!turnMade) {
checkTwoInDiagonalsB(turnMade, 'O', 'O');
}
if (!turnMade) {
checkTwoInDiagonalsF(turnMade, 'O', 'O');
}
//Computer checks if the player can be blocked
if (!turnMade) {
checkColumn(turnMade, 'X');
}
if (!turnMade) {
checkRow(turnMade, 'X');
}
if (!turnMade) {
checkTwoInDiagonalsB(turnMade, 'X', 'O');
}
if (!turnMade) {
checkTwoInDiagonalsF(turnMade, 'X', 'O');
}
//Computer makes random move
if (!turnMade) {
compRandInput();
}
//Reset board with new marking
drawBoard();
}
void checkWin(char symbol) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
//Column
if (i == 0 && numbers[i][j] == symbol) {
if (numbers[i + 1][j] == symbol && numbers[i + 2][j] == symbol) {
gameOver = true;
}
}
//Row
if (j == 0 && numbers[i][j] == symbol) {
if (numbers[i][j + 1] == symbol && numbers[i][j + 2] == symbol) {
gameOver = true;
}
}
//Diagonal
if (i == 0 && j == 0 && numbers[i][j] == symbol) {
if (numbers[i + 1][j + 1] == symbol && numbers[i + 2][j + 2] == symbol) {
gameOver = true;
}
}
if (i == 0 && j == 2 && numbers[i][j] == symbol) {
if (numbers[i + 1][j - 1] == symbol && numbers[i + 2][j - 2] == symbol) {
gameOver = true;
}
}
}
}
}
void checkCatsGame() {
bool catsGame = true;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (numbers[i][j] != 'X' && numbers[i][j] != 'O') {
catsGame = false;
}
}
}
if (catsGame) {
gameOver = true;
}
}
int main() {
srand(time(0));
drawBoard();
while (!gameOver) {
checkCatsGame();
if (gameOver) {
endText = "Cat's game! ";
break;
}
playerInput();
checkWin('X');
if (gameOver) {
endText = "You win! ";
break;
}
checkCatsGame();
if (gameOver) {
endText = "Cat's game! ";
break;
}
compInput();
checkWin('O');
if (gameOver) {
endText = "You lose. ";
break;
}
}
std::cout << endText << "Press enter to exit the console." << std::endl;
std::cin.get();
std::cin.get();
return 0;
}
std::cout
. Loads of things to improve. \$\endgroup\$