Stuck in an Infinite Loop

Does anyone mind giving this a look and help me spot my logic error? I am able to compile and play a tic tac toe game, however the winning condition isn't checked nor is the DRAW condition. I tried running this through Python Tutor to visualize but my code is too long? Anyway...

board.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#ifndef BOARD_HPP
#define BOARD_HPP

enum GameState {X_WON, O_WON, DRAW, UNFINISHED};

class Board
{
	private:
		char gameBoard[3][3];
		char winner;
		int turn;

	public:
		Board();
		bool makeMove(int, int, char);
		int gameState();
		void print();
};
#endif 

board.cpp
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
#include<iostream>
#include "Board.hpp"
using std::cout;
using std::cin;
using std::endl;



Board::Board()//default constructor to initialize the 3x3 array to empty
{
	int turn = 0;
	for (int row = 0; row < 3; row++) 
	{
		for (int col = 0; col < 3; col++)
	       	{
			gameBoard[row][col] = '.';
		}
	}
}
//reads x&y coords for the move input by the player, records move
bool Board::makeMove(int row, int col, char player)
{
	if (gameBoard[row][col] == '.')//if space is empty, record the move
	{
		gameBoard[row][col] = player;
		return true;
	}
	else
		return false; //space is already taken
}

int Board::gameState()
{
	for(int i = 0; i < 3; i++)
	{
		//loop through the rows to look for a winner
		if (gameBoard[i][0] != '.' && gameBoard[i][0] == gameBoard[i][1] 
		    && gameBoard[i][0] == gameBoard[i][2])
		{
			char winner = gameBoard[i][0];
		}
		//loop through the colums to look for a winner
		else if (gameBoard[0][i] != '.' && gameBoard[0][i] == 
			gameBoard[1][i] && gameBoard[0][i] == gameBoard[2][i])
		{
			char winner = gameBoard[0][i];
		}
	}
	turn++; //number of turns incrementer
	//check diagonals for a winner
	if (gameBoard[0][0] != '.' && gameBoard[0][0] == gameBoard[1][1]
	    && gameBoard[0][0] == gameBoard[2][2])
	{
		char winner = gameBoard[0][0];
	}
	else if (gameBoard[0][2] != '.' && gameBoard[0][2] == gameBoard[1][1]
		&& gameBoard[0][2] == gameBoard[2][0])
	{
		char winner = gameBoard[0][2];
	}
	//check for a draw(all spaces full)
	if (turn == 10)
	{
		return DRAW;
	}
	//if X won, return X as winner
	if (winner == 'x' || winner == 'X')
	{
		return X_WON;
	}
	//if O won, return O as winner
	if (winner == 'o' || winner == 'O')
	{
		return O_WON;
	}
	else return UNFINISHED; //game still in progress
}

void Board::print()//display the board to the screen
{
	cout << "  0 1 2" << endl;
	for (int row = 0; row < 3; row++)
	{
		cout << row << " ";
	
		for (int col = 0; col < 3; col++)
		{
			cout << gameBoard[row][col] << " ";
		}
		
		cout << endl; 
	}
}

TTT.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#ifndef TICTACTOE_HPP
#define TICTACTOE_HPP
#include "Board.hpp"

class TicTacToe
{
	private:
		char player;
		Board newGame;

	public:
		TicTacToe(char);
		void play();
};
#endif 

TTT.cpp
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
#include<iostream>
#include "TicTacToe.hpp"
using std::cout;
using std::cin;
using std::endl;

TicTacToe::TicTacToe(char player1)
{
	player = player1;
}

void TicTacToe::play()
{
	int gameState = newGame.gameState(); //int to hold relevant enum state
	int row;
	int col;

	do //loop that won't stop if gameState = UNFINISHED
	{
		cout << "Player " << player << 
			": Enter move as X then Y coordinates." << endl;
		newGame.print(); //display the board to the screen
		cin >> row >> col; //read player's input coordinates
		cout << endl;

		if (newGame.makeMove(row, col, player))
		{
			//returns current enum state based on new values input
			gameState = newGame.gameState();
			
			//if/else statement to swap players
			if (player == 'x')
			{
				player = 'o';
			}
			else
				player = 'x';
		}
		else
		{
			//let the player know that this space is taken
			cout << "That space is occupied, try another space. \n" 
			<< endl;
		}
	}
       	while (gameState == UNFINISHED);

	if (gameState == X_WON)
	{
		newGame.print();
		cout << "X won this game." << endl;
	}
	else if (gameState == O_WON)
	{
		newGame.print();
		cout << "O won this game." << endl;
	}
	else if (gameState == DRAW)
	{
		newGame.print();
		cout << "Bummer, this game is a draw..." << endl;
	}
}


int main()
{	
	char player;
	cout << "Which player would like to go first, X or O?" << endl;
	cin >> player;
	
	if (player == 'x' || player == 'X' || player == 'o' || player == 'O')
	{
		TicTacToe newGame(player);
		newGame.play();
	}	
	
	return 0;
}
Last edited on
I guess that the variable winner (line 36/40) is a global variable.

Line 9/15/23/28 you create local variables with the same name. They shadow the global variable of the same name and thus do not change the content of winner used on line 36/40.

Remove the type (char) on line 9/15/23/28 so that the global winner is modified.
I included all of my code for full visibility. I'll change the local variables, but shouldn't the counter be incrementing as well which would eventually get to the DRAW condition?

Thanks again.
Bumping for visibility, let me know if that is against forum rules...
I included all of my code for full visibility. I'll change the local variables, but shouldn't the counter be incrementing as well which would eventually get to the DRAW condition?

The turn member of Board is not initialized to any specific value, so it may be any value to begin with, and it make take quite a few increments to eventually get to the DRAW condition.

Creating a local variable in the constructor with the same name as the member and setting it to a value does not affect the member variable, much like hitting a person name John Smith in the face doesn't give some other John Smith a bloody nose.

Mentioning the name of what you referred to as "the counter" would've been useful.
Last edited on
I'll change the local variables
What did you change? What about lines 9/15/23/28 now 40/46/54/59?

Again: winner is not needed as a member variable since you use it in a single function only. You just need to avoid the shadowing.
I've rewritten my code because I was trying to make too many changes to the existing code and was getting myself too confused, I've included it below but I now can't compile, I'm getting an error that I'm illegally declaring a function definition on line 119 and I need a } on line 132 of board.cpp, but I do have those there??? And I'm not declaring a function? Only board.h and board.cpp have been modified which is why I'm not including TTT.h or TTT.cpp
***Ignore that, I was missing an } in a previous definition. I'm leaving this post up in case others come along having a similar problem*** I can delete instead if that is what mods prefer.
board.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#ifndef BOARD_HPP
#define BOARD_HPP

enum gameState {X_WON, O_WON, DRAW, UNFINISHED};

class Board
{
	private:
		char gameBoard[3][3];
		int turn;

	public:
		Board();
		bool makeMove(int, int, char);
		int gameState();
		void print();
};
#endif 

board.cpp
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
#include<iostream>
#include "Board.hpp"
using std::cout;
using std::cin;
using std::endl;

Board::Board()//default constructor to initialize the 3x3 array to empty
{
	for (int row = 0; row < 3; row++) 
	{
		for (int col = 0; col < 3; col++)
	       	{
			gameBoard[row][col] = '.';
		}
	}
}
//reads x&y coords for the move input by the player, records move
bool Board::makeMove(int row, int col, char player)
{
	if (gameBoard[row][col] == '.')//if space is empty, record the move
	{
		gameBoard[row][col] = player;
		return true;
	}
	else
		return false; //space is already taken
}

int Board::gameState()
{
	char playerX = UNFINISHED;
	char playerO = UNFINISHED;

	for(int i = 0; i < 3; i++)
	{
		//loop through the rows to look for a winner
		if (gameBoard[i][0] == 'x' && gameBoard[i][1] == 'x' 
		    && gameBoard[i][2] == 'x')
		{
			playerX = X_WON;
		}
		else if (gameBoard[i][0] == 'o' && gameBoard[i][1] == 'o' 
		    && gameBoard[i][2] == 'o')
		{
			playerO = O_WON;
		}
	}
	
	for (int i = 0; i< 3; i++)
	{
		//loop through the colums to look for a winner
		if (gameBoard[0][i] == 'x' && gameBoard[1][i] == 'x'
		&& gameBoard[2][i] == 'x')
		{
			playerX = X_WON;
		}
		else if (gameBoard[0][i] == 'o' && gameBoard[1][i] == 'o'
		&& gameBoard[2][i] == '0')
		{
			playerO = O_WON;

	}
	//check diagonals for a winner
	if (gameBoard[0][0] == 'x' && gameBoard[1][1] == 'x'
	    && gameBoard[2][2] == 'x')
	{
		playerX = X_WON;
	}
	else if (gameBoard[0][0] == 'o' && gameBoard[1][1] == 'o'
	    && gameBoard[2][2] == 'o')
	{
		playerO = O_WON;
	}

	if (gameBoard[0][2] == 'x' && gameBoard[1][1] == 'x'
		&& gameBoard[2][0] == 'x')
	{
		playerX = X_WON;
	}
	else if (gameBoard[0][2] == 'o' && gameBoard[1][1] == 'o'
		&& gameBoard[2][0] == 'o')
	{
		playerO = O_WON;
	}

	//check for a draw(all spaces full)
	int emptyspaces = 0;
	for(int i = 0;i < 3;i++)
	{
        	for(int j =0;j < 3;j++)
		{
           		if(gameBoard[i][j] != '.')
	    		{
                		emptyspaces++;
            		}
        	}
	}	
	//if X won, return X as winner
	if (playerX == X_WON && playerO == UNFINISHED)
	{
		return X_WON;
	}
	//if O won, return O as winner
	else if (playerO == O_WON && playerX == UNFINISHED)
	{
		return O_WON;
	}
	else if (emptyspaces == 9)
	{
		return DRAW; //return a tie game
	}
	else if (playerX == UNFINISHED && playerO == UNFINISHED)
	{
		return UNFINISHED; //game still in progress
	}
}

void Board::print()//display the board to the screen
{
	cout << "  0 1 2" << endl;
	for (int row = 0; row < 3; row++)
	{
		cout << row << " ";
	
		for (int col = 0; col < 3; col++)
		{
			cout << gameBoard[row][col] << " ";
		}
		
		cout << endl; 
	}
}

Last edited on
Topic archived. No new replies allowed.