Tic Tac Toe Program w/ 2D Array - Help Needed!

Apr 10, 2020 at 10:41pm
If someone could help me sort this out I would be extremely grateful! I am trying to put the finishing touches on this Tic Tac Toe program using a 2D array and I can't seem to figure out what I am doing wrong. Even looking at the million other versions posted in forums across the web I can't figure out exactly what I am missing...

The program compiles and runs fine right now but I can't get it to switch from "Player X" to "Player O", and I've tried a bunch of different solutions.

Thanks in advance for your help guys!

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
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
#include <iostream>
#include <string.h>
using namespace std;

// Constant variable definitions
const int ARRAY_SIZE = 9;
const int ROWS = 3;
const int COLS = 3;

// Function prototypes
void displayBoard(char [][COLS]);      // displays the board
void playerTurn();  // places X or O in correct location
void togglePlayer();  // switches player turn from X to O, and vice versa
void displayWinner(char []);     // uses playerWins() to display winner
char playerWins();  // checks to see if either X or O won
bool checkForCatGame(char []);   // checks to see if no moves are remaining
bool gameOver(char []);          // checks for loss with playerWins() + checkForCatGame()

// Gameboard array definitions
char gameBoard[ROWS][COLS] = {{ '-', '-', '-' },{ '-', '-', '-' },{ '-', '-', '-' }};

/****************************************************************************
   main() function
*****************************************************************************/

int main()
{
   char player = 'X';
   char gameWinner = ' ';
   int choice, row, column;
   bool tie = false;

   displayBoard(gameBoard);

   while (1)
   {
      playerTurn();
      displayBoard(gameBoard);

      if (playerWins() == 'X')
      {
         cout << "Player X wins!" << endl;
         break;
      }
      else if (playerWins() == 'O')
      {
         cout << "Player O wins!" << endl;
         break;
      }

      togglePlayer();

   }

   return 0;
}

/****************************************************************************
   displayBoard() function displays contents of the game board
*****************************************************************************/

void displayBoard(char gameBoard[][COLS])
{
   cout << "       Column\n" << "        1 2 3\n";

   for (int r = 0; r < ROWS; r++)
   {
      cout << "Row " << (r + 1) << ":  ";

      for (int c = 0; c < COLS; c++)
      {
         cout << gameBoard[r][c] << " ";
      }

      cout << endl;
   }

}

/****************************************************************************
   playerTurn() function places an 'X' or 'O' in the selected row/column
*****************************************************************************/

void playerTurn()
{
   char player = 'X';
   int rowChoice, colChoice;
   int row = 0;
   int column = 0;

   togglePlayer();

   if (player == 'X')
   {
         cout << endl;
         cout << "Player X's turn." << endl;
         cout << "Enter a row & column number." << endl;
   }
   else if(player == 'O')
   {
      cout << "Player O's turn." << endl;
      cout << "Enter a row and column to place an 'O'" << endl;
   }

   cout << "Row: ";
   cin >> rowChoice;

   switch(rowChoice)
   {
      case 1: row = 0; break;
      case 2: row = 1; break;
      case 3: row = 2; break;

      default:
         cout << "Invalid selection. Try again.\n";
         playerTurn();
   }

   cout << "Column: ";
   cin >> colChoice;
   cout << endl << endl;

   switch(colChoice)
   {
      case 1: column = 0; break;
      case 2: column = 1; break;
      case 3: column = 2; break;

      default:
         cout << "Invalid selection. Try again.\n";
         playerTurn();
   }

   if (player == 'X' && row != 'X' && row != 'O' && column != 'X' && column != 'O')
   {
      gameBoard[row][column] = 'X';
      togglePlayer();
   }
   else if (player == 'O' && row != 'X' && row != 'O' && column != 'X' && column != 'O')
   {
      gameBoard[row][column] = 'O';
      togglePlayer();
   }
   else
   {
      cout << "Your selection has already been chosen. Try again.\n";
      playerTurn();
   }
}

/****************************************************************************
   togglePlayer() switches player turn from 'X' to 'O' and vice versa
*****************************************************************************/

void togglePlayer()
{
   char player;

   if (player == 'X')
      player = 'O';
   else
      player = 'X';
}

/****************************************************************************
   playerWins() returns "X" or "O" if that player has won
*****************************************************************************/

char playerWins()
{
   // Checking each row in the array for three consecutive (3) X's
   if (gameBoard[0][0] == 'X' && gameBoard[0][1] == 'X' && gameBoard[0][2] == 'X')
      return 'X';
   if (gameBoard[1][0] == 'X' && gameBoard[1][1] == 'X' && gameBoard[1][2] == 'X')
      return 'X';
   if (gameBoard[2][0] == 'X' && gameBoard[2][1] == 'X' && gameBoard[2][2] == 'X')
      return 'X';

   // Checking each column in the array for three consecutive (3) X's
   if (gameBoard[0][0] == 'X' && gameBoard[1][0] == 'X' && gameBoard[2][0] == 'X')
      return 'X';
   if (gameBoard[0][1] == 'X' && gameBoard[1][1] == 'X' && gameBoard[2][1] == 'X')
      return 'X';
   if (gameBoard[0][2] == 'X' && gameBoard[1][2] == 'X' && gameBoard[2][2] == 'X')
      return 'X';

   // Checking across the array diagonally for three (3) consective X's
   if (gameBoard[0][0] == 'X' && gameBoard[1][1] == 'X' && gameBoard[2][2] == 'X')
      return 'X';
   if (gameBoard[2][0] == 'X' && gameBoard[1][1] == 'X' && gameBoard[0][2] == 'X')
      return 'X';

   // Checking each row in the array for three consecutive (3) O's
   if (gameBoard[0][0] == 'O' && gameBoard[0][1] == 'O' && gameBoard[0][2] == 'O')
      return 'O';
   if (gameBoard[1][0] == 'O' && gameBoard[1][1] == 'O' && gameBoard[1][2] == 'O')
      return 'O';
   if (gameBoard[2][0] == 'O' && gameBoard[2][1] == 'O' && gameBoard[2][2] == 'O')
      return 'O';

   // Checking each column in the array for three consecutive (3) O's
   if (gameBoard[0][0] == 'O' && gameBoard[1][0] == 'O' && gameBoard[2][0] == 'O')
      return 'O';
   if (gameBoard[0][1] == 'O' && gameBoard[1][1] == 'O' && gameBoard[2][1] == 'O')
      return 'O';
   if (gameBoard[0][2] == 'O' && gameBoard[1][2] == 'O' && gameBoard[2][2] == 'O')
      return 'O';

   // Checking across the array diagonally for three (3) consective O's
   if (gameBoard[0][0] == 'O' && gameBoard[1][1] == 'O' && gameBoard[2][2] == 'O')
      return 'O';
   if (gameBoard[2][0] == 'O' && gameBoard[1][1] == 'O' && gameBoard[0][2] == 'O')
      return 'O';

   return '/';
}
Last edited on Apr 10, 2020 at 10:44pm
Apr 10, 2020 at 11:03pm
Toggleplayer does not take any parameters. What player exactly, is it toggling? Its not the local one in main. You need to pass, by reference, player from main into it, and lose the local copy.

Or, honestly, just do that in main and forget the function entirely.
make main's player a bool, and say player =!player to reverse which one it is. If its true, its X, if false, its O. That same ideal cleans up all that 'X' and 'O' clutter while you are at it.

Remember that playerturn also does the exact same thing. You need to pass player into it as well, same issue. You also need to toggle either in main or in player turn but not both. A double toggle has no effect.
Last edited on Apr 10, 2020 at 11:10pm
Apr 11, 2020 at 5:03am
1
2
3
4
5
char playerWins()
{
   // Checking each row in the array for three consecutive (3) X's
   if (gameBoard[0][0] == 'X' && gameBoard[0][1] == 'X' && gameBoard[0][2] == 'X')
      return 'X';


You already know the player who just made a move. The opponent cannot win just on your move.
1
2
3
4
5
char playerWins(char player)
{
   // Checking each row in the array for three consecutive (3) X's
   if (gameBoard[0][0] == player && gameBoard[0][1] == player && gameBoard[0][2] == player)
      return player;

This halves the length of your function at a stroke.


Apr 11, 2020 at 5:10pm
Thanks for your help guys. I implemented both changes but I still can't get the program to stop and display a winner once there is one. The logic appears to be correct in the playerWins function. The only thing I can think of is maybe the value isn't being passed correctly from playerTurn, but I can't seem to find the mistake.

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>
#include <string.h>
using namespace std;

// Constant variable definitions
const int ARRAY_SIZE = 9;
const int ROWS = 3;
const int COLS = 3;

// Function prototypes
void displayBoard(char [][COLS]);      // displays the board
void playerTurn(char);  // places X or O in correct location
void displayWinner(char []);     // uses playerWins() to display winner
char playerWins(char);  // checks to see if either X or O won
bool checkForCatGame(char []);   // checks to see if no moves are remaining
bool gameOver(char []);          // checks for loss with playerWins() + checkForCatGame()

// Gameboard array definitions
char gameBoard[ROWS][COLS] = {{ '-', '-', '-' },{ '-', '-', '-' },{ '-', '-', '-' }};

/****************************************************************************
   main() function
*****************************************************************************/

int main()
{
   char player = 'X';
   int choice, row, column;
   char winner = playerWins(player);

   while (playerWins(player) != 'X' && playerWins(player) != 'O')
   {
      playerTurn(player);
   }

   if (playerWins(player) == 'X' && playerWins(player) == 'O')
   {
      cout << "Player " << playerWins(player) << " wins!" << endl;
   }
   else
   {
      playerTurn(player);
   }

   return 0;
}

/****************************************************************************
   displayBoard() function displays contents of the game board
*****************************************************************************/

void displayBoard(char gameBoard[][COLS])
{
   cout << "       Column\n" << "        1 2 3\n";

   for (int r = 0; r < ROWS; r++)
   {
      cout << "Row " << (r + 1) << ":  ";

      for (int c = 0; c < COLS; c++)
      {
         cout << gameBoard[r][c] << " ";
      }

      cout << endl;
   }
}

/****************************************************************************
   playerTurn() function places an 'X' or 'O' in the selected row/column
*****************************************************************************/

void playerTurn(char player)
{
   int rowChoice, colChoice;
   int row = 0;
   int column = 0;

   displayBoard(gameBoard);

   if (player == 'X')
   {
         cout << endl;
         cout << "Player X's turn." << endl;
         cout << "Enter a row & column number." << endl;
   }
   else if(player == 'O')
   {
      cout << "Player O's turn." << endl;
      cout << "Enter a row and column to place an 'O'" << endl;
   }

   cout << "Row: ";
   cin >> rowChoice;

   switch(rowChoice)
   {
      case 1: row = 0; break;
      case 2: row = 1; break;
      case 3: row = 2; break;

      default:
         cout << "Invalid selection. Try again.\n";
         playerTurn(player);
   }

   cout << "Column: ";
   cin >> colChoice;
   cout << endl << endl;

   switch(colChoice)
   {
      case 1: column = 0; break;
      case 2: column = 1; break;
      case 3: column = 2; break;

      default:
         cout << "Invalid selection. Try again.\n";
         playerTurn(player);
   }

   if (player == 'X' && row != 'X' && row != 'O' && column != 'X' && column != 'O')
   {
      gameBoard[row][column] = 'X';
      playerWins(player);
      player = 'O';
   }
   else if (player == 'O' && row != 'X' && row != 'O' && column != 'X' && column != 'O')
   {
      gameBoard[row][column] = 'O';
      playerWins(player);
      player = 'X';
   }
   else
   {
      cout << "That cell has been previously selected. Try again.\n";
      playerTurn(player);
   }

   playerTurn(player);
}

/****************************************************************************
   playerWins() returns "true" if the player has won
*****************************************************************************/

char playerWins(char player)
{
   // Checking each of the three (3) horizontal rows for a winner
   if (gameBoard[0][0] == player && gameBoard[0][1] == player && gameBoard[0][2] == player)
      return player;
   if (gameBoard[1][0] == player && gameBoard[1][1] == player && gameBoard[1][2] == player)
      return player;
   if (gameBoard[2][0] == player && gameBoard[2][1] == player && gameBoard[2][2] == player)
      return player;

   // Checking each of the three (3) vertical rows for a winner
   if (gameBoard[0][0] == player && gameBoard[1][0] == player && gameBoard[2][0] == player)
      return player;
   if (gameBoard[0][1] == player && gameBoard[1][1] == player && gameBoard[2][1] == player)
      return player;
   if (gameBoard[0][2] == player && gameBoard[1][2] == player && gameBoard[2][2] == player)
      return player;

   // Checking diagonally across the array for a winner
   if (gameBoard[0][0] == player && gameBoard[1][1] == player && gameBoard[2][2] == player)
      return player;
   if (gameBoard[2][0] == player && gameBoard[1][1] == player && gameBoard[0][2] == player)
      return player;
}

/****************************************************************************
   ...
*****************************************************************************/
Last edited on Apr 11, 2020 at 5:13pm
Apr 12, 2020 at 3:27am
> playerWins() returns "true" if the player has won
What does it return if the player hasn't won?

> if (player == 'X' && row != 'X' && row != 'O' && column != 'X' && column != 'O')
row and column are integers in the range 0 to 3, not players.

1
2
3
4
5
6
7
8
9
10
   switch(colChoice)
   {
      case 1: column = 0; break;
      case 2: column = 1; break;
      case 3: column = 2; break;

      default:
         cout << "Invalid selection. Try again.\n";
         playerTurn(player);
   }

DON'T use recursion to implement a while loop.
1. It will just ask you for the row again, and you already did that.
2. You have to deal with the recursion eventually ending, with whatever junk you thought you were avoiding to begin with.


Topic archived. No new replies allowed.