How to determine winner in my Tic Tac Toe program

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
#include <iostream>
#include <string>
#include <cctype>

using namespace std;

//routine to display the current tic tac toe board
void PrintBoard(string board);

//routine to let player X or O make a move and return the updated board
string PickMove(string board, char player);

//
bool checkForGameEnd(string board);

//constant to record the size of the board
const int boardSize = 9;

//the main routine initializes the tic tac toe board
// and runs the first two moves of the game
int main()
{
   
    
    //setup the initial tic tac toe board
    string Board = "012345678";
    cout << endl;
    PrintBoard(Board);
    
    char currentPlayer = 'X';
    
    do {
        //let the current player make a move
        Board = PickMove(Board, currentPlayer);
        PrintBoard(Board);
        
        //switch players
        if (currentPlayer == 'X')
        {
            currentPlayer = 'O';
        }
        else
        {
            currentPlayer = 'X';
        }
    } while (!checkForGameEnd(Board));
    
    //exit the program
    return 0;

}

//routine to let player X or O make a move and return the updated board
//parameter 'player' contains 'X' or 'O', indicating whose turn it is

string PickMove(string board, char player)
{
    //prompt the current player for their move
    cout << endl;
    cout << "Player " << player << "\'s turn" << endl;
    cout << "Pick an unclaimed board position 0-8:" << endl;
    
    //read in the players choice
    int moveChosen;
    cin >> moveChosen;
    
    //if the players choice isnt in the range 0-8, display an error 
    //   message and issue a new call to PickMove and update the board 
    if (moveChosen > 8 || moveChosen < 0)
    {
        cout << "_____________________________________________________";
        cout << "____________" << endl;    
        cout << moveChosen << " is an invalid choice, ";
        cout << "your choice must be in the range (0-8)" << endl;
        board = PickMove (board, player);
    }
    
    //otherwise, if the spot the player chose has already been taken, then
    //  display an error message, issue a new call to PickMove
    //  and update the board
    else if (!isdigit (board[moveChosen]))
    {
        cout << "_____________________________________________________";
        cout << "____________" << endl;    
        cout << moveChosen << " is an invalid choice, ";
        cout << "you must choose a spot that isnt already taken" << endl;
        board = PickMove (board, player); 
    }
    //otherwise put the players choice on the chosen spot
    else board [moveChosen] = player;
        cout << endl;
        //return the updated board;
        return board;
        

}

//rountine to display the current tic tac toe board
void PrintBoard(string board)
{
    //display the top row of the board 
    cout << "| " << board[0];
    cout << " | " << board[1];
    cout << " | " << board[2];
    cout << " | " << endl;
    
    //display the middle row of the board
    cout << "+---+---+---+" << endl;
    cout << "| " << board[3];
    cout << " | " << board[4];
    cout << " | " << board[5];
    cout << " | " << endl;
    
    //display the bottom row of the board
    cout << "+---+---+---+" << endl;
    cout << "| " << board[6];
    cout << " | " << board[7];
    cout << " | " << board[8];
    cout << " | " << endl;
}

//Return true if the game is over, false otherwise
bool checkForGameEnd(string board)
{
    //check if all board positions are full, in which case game is over
    
    //count the number of filled positions
    
    int positionsFilled = 0;
    
    for (int pos = 0; pos < boardSize; pos++)
    {
        if ((board[pos] == 'X') || (board[pos] == 'O'))
        {
            positionsFilled++;
        }
    }
    
    //perform the check for a full board
    
    if (positionsFilled == boardSize)
    {
        return true;
    }
    
    //otherwise the game is not over
    
    return false;
}


Here is what it looks like:

| 0 | 1 | 2 | 
+---+---+---+
| 3 | 4 | 5 | 
+---+---+---+
| 6 | 7 | 8 | 

Player X's turn
Pick an unclaimed board position 0-8:
0

| X | 1 | 2 | 
+---+---+---+
| 3 | 4 | 5 | 
+---+---+---+
| 6 | 7 | 8 | 

Player O's turn
Pick an unclaimed board position 0-8:
1

| X | O | 2 | 
+---+---+---+
| 3 | 4 | 5 | 
+---+---+---+
| 6 | 7 | 8 | 

Player X's turn
Pick an unclaimed board position 0-8:
3

| X | O | 2 | 
+---+---+---+
| X | 4 | 5 | 
+---+---+---+
| 6 | 7 | 8 | 

Player O's turn
Pick an unclaimed board position 0-8:
2

| X | O | O | 
+---+---+---+
| X | 4 | 5 | 
+---+---+---+
| 6 | 7 | 8 | 

Player X's turn
Pick an unclaimed board position 0-8:
6

| X | O | O | 
+---+---+---+
| X | 4 | 5 | 
+---+---+---+
| X | 7 | 8 | 

Player O's turn
Pick an unclaimed board position 0-8:


I just entered enough for player X to win..

Do i imput the code for determining the winnner in my PickMove function, or in the main??

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
	if (spot[0] && spot[1] && spot[2] == 'X')
		return true;
	else if(spot[3] && spot[4] && spot[5] == 'X')
		return true;
	else if(spot[6] && spot[7] && spot[8] == 'X')
		return true;
	else if(spot[0] && spot[4] && spot[8] == 'X')
		return true;
	else if(spot[2] && spot[4] && spot[6] == 'X')
		return true;
	else if(spot[0] && spot[3] && spot[6] == 'X')
		return true;
	else if(spot[1] && spot[4] && spot[7] == 'X')
		return true;
	else if(spot[2] && spot[5] && spot[8] == 'X')
		return true;


This is from the program I wrote a while back, just replace 'spot' with 'board' to match your code. It seems to work, but I couldn't get the AI to work right so I didn't get to play any true games to test it right.
I tried adding that and tweaking it but still nothings working.. this is what i did

I added a function that would check if there was three X or O in a row, and if that was true then

EDIT**

I realized that the condition for checking if there was three in a row should be in my checkForGameEnd function, so now it will leave the loop for both options. I still dont understand how to determine WHO won..

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
bool checkForGameEnd(string board)
{
    //check if all board positions are full, in which case game is over
    
    //count the number of filled positions
    int positionsFilled = 0;
    
    for (int pos = 0; pos < boardSize; pos++)
    {
        if ((board[pos] == 'X') || (board[pos] == 'O'))
        {
            positionsFilled++;
        }
    }
    
    for (char player)
    
    //perform the check for a full board
    if (positionsFilled == boardSize)
    {
        return true;
    }  
    if (board[0] == board[1] && board[1] == board[2])
    {
		return true;
    }
	if (board[3] == board[4] && board[4] == board[5])
	{
		return true;
	}
	if (board[6] == board[7] && board[7] == board[8])
	{
		return true;
	}
	if (board[0] == board[3] && board[3] == board[6])
	{
		return true;
	}
	if (board[1] == board[4] && board[4] == board[7])
	{
		return true;
	}
	if (board[2] == board[5] && board[5] == board[8])
	{
		return true;
	}
	if (board[0] == board[4] && board[4] == board[8])
	{
		return true;
	}
	if (board[2] == board[4] && board[4] == board[6])
	{
		return true;
    }
    
    //otherwise the game is not over
    return false;
    
   
}
Last edited on
I find it much easier to use a 2d array for the board. This makes the logic much easier for things like CheckDiag function, which looks at [0][0], [1][1], [2][2]. This can be done with a nested for loop. This is easier top program than checking positions 0,5 & 8 for example.

To check for a win, you need to check each row, each column, and both diagonals - I would make these separate functions called from the CheckWin function.


Check out this reply I made to another Tic Tac Toe person:
http://www.cplusplus.com/forum/beginner/81293/2/#msg439176

If you make all these changes, then you could have compact, elegant code, rather than a long series of if statements to do the logic.

Hope all goes well.
Without looking at much of your code/problems at all, the simplest way I can think to figure out who won is to change the return type to char, and end up with something like this:
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
char checkForGameEnd(string board)
{
    //...
    
    //perform the check for a full board
    if (positionsFilled == boardSize)
    {
        return 'E';
    } 
  
    if (board[0] == board[1] && board[1] == board[2])
    {
		return board[0];
    }
    else if //..

   return 'N'
}


// back in main()

switch (checkForGameEnd(string board))
{
case 'E':  cout << "Its a draw\n";  break;
case 'X':  cout << "X wins\n"; break;
case 'O':  cout << "O wins\n"; break;
case 'N':  cout << "Keep playing\n"; break; // or maybe say nothing
default:  cout << "Error in checkForGameEnd()\n";
}




Here's a possible solution for your perusal. While I would disgree on TheIdeasman's notion that a 2d array for the board would lead to more elegant code, I did manage to find a use for one.

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
enum Winner { NOBODY_WON, X_WON, Y_WON } ;

typedef int triplet[3] ;  // a triplet is a 3 element array of int
const triplet triplets[] = 
{
    { 0, 1, 2 }, { 3, 4, 5 }, { 6, 7, 8 },  // horizontal
    { 0, 3, 6 }, { 1, 4, 7 }, { 2, 5, 8 },  // vertical
    { 0, 4, 8 }, { 2, 5, 8 }                // diagonal
}; 
const unsigned numTriplets = sizeof(triplets) / sizeof(triplets[0]) ;


Winner checkTriplet( const string& board, const triplet & t )
{
    if ( board[t[0]] == board[t[1]]  &&  board[t[1]] == board[t[2]] )
    {
        if ( board[t[0]] == 'X' )
            return X_WON ;
        else
            if ( board[t[0]] == 'Y' )
                return Y_WON ;
    }
    return NOBODY_WON ;
}


bool boardIsFull(const string& board)
{
    for ( unsigned i=0 ; i< boardSize ; ++i )
        if ( board[i] != 'X' && board[i] != 'Y' )
            return false ;
    return true ;
}


Winner checkForWinner(const string&  board)
{
    for ( unsigned i=0; i< numTriplets; ++i )
    {
        Winner possibleWinner = checkTriplet(board, triplets[i]) ;
        if ( possibleWinner != NOBODY_WON )
            return possibleWinner ;
    }
    return NOBODY_WON ;
}



in main:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
    // ...
    do {
          // ...
    } while ( !boardIsFull(board) && NOBODY_WON == checkForWinner(board) ) ;

    switch( checkForWinner(board) )
    {
    case NOBODY_WON:
         // ...
    case X_WON:
        // ...
    case Y_WON:
        // ...
    }
Topic archived. No new replies allowed.