Thread: infinite loop due to incorrect input

  1. #1
    Registered User
    Join Date
    Nov 2007
    Posts
    164

    infinite loop due to incorrect input

    Code:
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    // global constants
    const char X = 'X';
    const char O = 'O';
    const char EMPTY = ' ';
    const char TIE = 'T';
    const char NO_ONE = 'N';
    
    // game function's prototypes
    void displayBoard(const vector<char>& board); // function that displays the game board
    char choosePiece(); // function to let the user choose their pieces
    char winner(const vector<char>& board); // determines the game winner
    char firstMove(const char& player1, const char& player2); // function that determines who makes the first move
    int playerOneMove(const vector<char>& board, const char player1); // returns the move of player1
    int playerTwoMove(const vector<char>& board, const char player2); // returns the move of player2
    
    int main()
    {
    	// vector that holds the game board
    	vector<char> board(9, EMPTY); // there are only 9 positions in a tic-tac-toe board so a vector with 9 elements is fine
    	//and initialized all elements with the EMPTY char
    
    	// show the instructions
    	// this is how the board would look like
    	cout << "\n\n" << 0 << " | " << 1 << " | " << 2 << endl;
    	cout << "---------" << endl;
    	cout << 3 << " | " << 4 << " | " << 5 << endl;
    	cout << "---------" << endl;
    	cout << 6 << " | " << 7 << " | " << 8 << endl;
    
    	cout << "\n\nThe above is the game board" << endl;
    	cout << "To put your piece in the center of the game board, enter number 4."
    	 	 << "\nTo put your piece elsewhere in the board, then enter its corresponding position"
    	 	 << "\nnumber as illustrated in the diagram above" << endl;
    
    
    
    	char player1, player2;
    	player1 = choosePiece();
    
    	// player1 has chosen its piece now chose the opposite piece of player1 for player2
    	if (player1 == 'X')
    	{
    		player2 = 'O';
    	}
    	else {
    		player2 = 'X';
    	}
    
    	cout << "\n\nPlayer 1's piece is " << player1 << endl;
    	cout << "Player 2's piece is " << player2 << endl;
    
    	char turn; // variable to store whose turn it is
    
    	turn = firstMove(player1, player2); // who goes first, returns either X or O
    
    	cout << "\n\nGood luck to both of the players!" << endl;
    
    	// while nobody has one the game and its not a tie
    	while (winner(board) == NO_ONE)
    	{
    		int move;
    		
    		displayBoard(board);
    		
    		if (turn == player1)
    		{
    			move = playerOneMove(board, player1);
    			board[move] = player1;
    			turn = player2;
    		}
    		else
    		{
    			move = playerTwoMove(board, player2);
    			board[move] = player2;
    			turn = player1;
    		}
    	}
    	
    	displayBoard(board);
    	cin.ignore();
    	cout << "\n\nPress Enter...";
    	cin.get();
    	cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n" << endl;	
    	cout << "\n                              " << winner(board) << " has won the game!" << endl;
    	cin.ignore();
    	cout << "Press Enter to Exit...";
    	cin.get();
    }
    
    void displayBoard(const vector<char>& board)
    {
    	cout << "\n\n" << board[0] << " | " << board[1] << " | " << board[2] << endl;
    	cout << "---------" << endl;
    	cout << board[3] << " | " << board[4] << " | " << board[5] << endl;
    	cout << "---------" << endl;
    	cout << board[6] << " | " << board[7] << " | " << board[8] << endl;
    
    }
    
    char choosePiece()
    {
    	cout << "\n\nPiece 1 = X" << endl;
    	cout << "Piece 2 = O" << endl;
    
    	char piece;
    
    	cout << "Enter a number to choose your piece [1-2]: " << endl;
    	cin >> piece;
    
    	if (piece == '1')
    	{
    		return X;
    	}
    	else {
    		return O;
    	}
    }
    
    char winner(const vector<char>& board)
    {
    	// multi-dimensional array that holds all possible winning rows
    	int WINNING_ROWS[8][3] = { {0, 1, 2},
    							   {3, 4, 5},
    							   {6, 7, 8},
    							   {0, 3, 6},
    							   {1, 4, 7},
    							   {2, 5, 8},
    							   {0, 4, 8},
    							   {2, 4, 6} };
    
    	const int TOTAL_ROWS = 8; // there are only 8 possible winning rows
    
    	// check to see if any winning row has three values that are the same and not empty
    	// then we have a winner and return the value of that row ( either X or O )
    	for (int i = 0; i < TOTAL_ROWS; i++)
    	{
    		if (board[WINNING_ROWS[i][0]] != EMPTY &&
    			board[WINNING_ROWS[i][0]] == board[WINNING_ROWS[i][1]] &&
    			board[WINNING_ROWS[i][1]] == board[WINNING_ROWS[i][2]])
    			{
    				return board[WINNING_ROWS[i][0]];
    			}
    	}
    
    	// since no body has won, check for a tie, that is there are no empty squares left
    	const int NUM_OF_POSITIONS = 9; // number of square in the game board
    	int emptyPositions = 0;
    
    	for (int i = 0; i < NUM_OF_POSITIONS; i++)
    	{
    		if (board[i] == EMPTY)
    		{
    			emptyPositions++;
    		}
    	}
    
    	// if there are no empty positions left in the board then the game is a tie
    	if (emptyPositions == 0)
    	{
    		return TIE;
    	}
    	else {
    		return NO_ONE; // it's neither a tie nor any player has won the game yet, the game is still remaining
    	}
    }
    
    char firstMove(const char& player1, const char& player2)
    {
    	char move;
    
    	cout << "\n\nWho will make the first move? " << player1 << " or " << player2 << " ?" << endl;
    	cout << "Enter "<< player1 << " or " << player2 << " : ";
    	cin >> move;
    
    
    
    	return toupper(move);
    }
    
    int playerOneMove(const vector<char>& board, const char player1)
    {
    	int move;
    	bool done = false;
    	for ( ; done != true ; )
    	{
    		cout << "\n" << player1 << " has to make the move" << endl;
    		cout << "Where will you move?" << " (0-" << board.size() - 1 << "): ";
    		bool checkInput = cin >> move;
    		
    		// Proceed only if input succeeds
    		if (checkInput)
    		{
    			
    			// if the move is less than zero or move is greater than 8 then print error message
    			// if move is 0 then it is not less than zero so no error, same goes for when move is 8
    			if (move < 0 || move > 8)
    			{
    				cout << "\n!!! No such move exists - try again !!!" << endl;
    				displayBoard(board);
    			}
    			// check if that move is legal, that is it is not filled with X or O
    			else if (board[move] != EMPTY)
    			{
    				cout << "\n!!! Place is taken - choose another position !!!" << endl;
    				displayBoard(board);
    			}
    			// if none of the if...else statements above are executed
    			// then initialize done with true value so that the for loop could execute
    			else
    			{
    				done = true;
    			}
    		}
    		else
    		{
    			cout << "\n!!! WRONG INPUT !!!" << endl;
    		}
    
    	}
    	return move;
    }
    
    int playerTwoMove(const vector<char>& board, const char player2)
    {
    	int move;
    	bool done = false;
    	for ( ; done != true ; )
    	{
    		cout << "\n" << player2 << " has to make the move" << endl;
    		cout << "Where will you move?" << " (0-" << board.size() - 1 << "): ";
    		bool checkInput = cin >> move;
    		
    		// Proceed only if input succeeds
    		if (checkInput)
    		{
    			// if the move is less than zero or move is greater than 8 then print error message
    			// if move is 0 then it is not less than zero so no error, same goes for when move is 8
    			if (move < 0 || move > 8)
    			{
    				cout << "\n!!! No such move exists - try again !!!" << endl;
    				displayBoard(board);
    			}
    			// check if that move is legal, that is it is not filled with X or O
    			else if (board[move] != EMPTY)
    			{
    				cout << "\n!!! Place is taken - choose another position !!!" << endl;
    				displayBoard(board);
    			}
    			// if none of the if...else statements above are executed
    			// then initialize done with true value so that the for loop could execute
    			else
    			{
    				done = true;
    			}
    		}
    		else
    		{
    			cout << "\n!!! WRONG INPUT !!!" << endl;
    		}
    	}
    	return move;
    }
    In the last two functions, (both are the same)

    When it asks for input, if one enters anything else than integer it starts looping infinitely?
    It first checks whether the input is correct or not

    What am I doing wrong here ?

  2. #2
    Registered User
    Join Date
    Nov 2007
    Posts
    57
    Why are you using a for loop? You can just use a while loop:

    Code:
    while ( done != true )
    And:

    Code:
    bool checkInput = cin >> move;
    How about:

    Code:
    cin >> move;
    if ( move >=0 || move <= 8 )
    {
    blah
    }
    I've never seen that check input thing you used before, so I'm not sure.

  3. #3
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    It's a for-loop because someone else suggested using a forever for loop and use break to break the look. Manzoor didn't like the concept of break, so decided to modify it. I agree, while is better if there is no initialization/update step of the loop.

    It loops forever if you attempt to read input and the input is incorrect, because incorrect input is still kept in the input buffer [numeric input in C and C++ reads all VALID digits, and stops as soon as the next character is not valid for the input]. You would need to use something like "cin.ignore()" to skip over the input (and perhaps cin.clear() to remove the error condition). Check the result of the input operation by doing something like
    Code:
    if (cin >> move) 
       // ok number, now check range etc.
    else
        cout << "Invalid input, please use numbers" << endl;
    --
    Mat
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  4. #4
    Registered User
    Join Date
    Jan 2005
    Posts
    7,366
    A simple, common technique to read integer input is:
    Code:
    int value = 0;
    while (!(cin >> value))
    {
        cin.ignore(numeric_limits<streamsize>::max(), '\n');
        cin.clear();
        // error message and re-prompt go here
    }
    // input succeeded so use value here
    You need to #include <limits> for numeric_limits and I think <ios> for streamsize. Or you can instead just use some large number like cin.ignore(10000, '\n') which will ignore up to 10,000 characters of bad input and should be enough for a simple application.

    The error checking can be expanded from here as well (to check for extra characters after the number for example).

  5. #5
    Registered User
    Join Date
    Nov 2007
    Posts
    164
    Code:
    #include <iostream>
    #include <vector>
    
    using namespace std;
    
    // global constants
    const char X = 'X';
    const char O = 'O';
    const char EMPTY = ' ';
    const char TIE = 'T';
    const char NO_ONE = 'N';
    
    // game function's prototypes
    void displayBoard(const vector<char>& board); // function that displays the game board
    char choosePiece(); // function to let the user choose their pieces
    char winner(const vector<char>& board); // determines the game winner
    char firstMove(const char& player1, const char& player2); // function that determines who makes the first move
    int playerOneMove(const vector<char>& board, const char player1); // returns the move of player1
    int playerTwoMove(const vector<char>& board, const char player2); // returns the move of player2
    
    int main()
    {
    	// vector that holds the game board
    	vector<char> board(9, EMPTY); // there are only 9 positions in a tic-tac-toe board so a vector with 9 elements is fine
    	//and initialized all elements with the EMPTY char
    
    	// show the instructions
    	// this is how the board would look like
    	cout << "\n\n" << 0 << " | " << 1 << " | " << 2 << endl;
    	cout << "---------" << endl;
    	cout << 3 << " | " << 4 << " | " << 5 << endl;
    	cout << "---------" << endl;
    	cout << 6 << " | " << 7 << " | " << 8 << endl;
    
    	cout << "\n\nThe above is the game board" << endl;
    	cout << "To put your piece in the center of the game board, enter number 4."
    	 	 << "\nTo put your piece elsewhere in the board, then enter its corresponding position"
    	 	 << "\nnumber as illustrated in the diagram above" << endl;
    
    
    
    	char player1, player2;
    	player1 = choosePiece();
    
    	// player1 has chosen its piece now chose the opposite piece of player1 for player2
    	if (player1 == 'X')
    	{
    		player2 = 'O';
    	}
    	else {
    		player2 = 'X';
    	}
    
    	cout << "\n\nPlayer 1's piece is " << player1 << endl;
    	cout << "Player 2's piece is " << player2 << endl;
    
    	char turn; // variable to store whose turn it is
    
    	turn = firstMove(player1, player2); // who goes first, returns either X or O
    
    	cout << "\n\nGood luck to both of the players!" << endl;
    
    	// while nobody has one the game and its not a tie
    	while (winner(board) == NO_ONE)
    	{
    		int move;
    		
    		displayBoard(board);
    		
    		if (turn == player1)
    		{
    			move = playerOneMove(board, player1);
    			board[move] = player1;
    			turn = player2;
    		}
    		else
    		{
    			move = playerTwoMove(board, player2);
    			board[move] = player2;
    			turn = player1;
    		}
    	}
    	
    	displayBoard(board);
    	cin.ignore();
    	cout << "\n\nPress Enter...";
    	cin.get();
    	cout << "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n                              " << winner(board) << " has won the game!\n\n\n\n\n\n\n\n\n\n\n\n" << endl;	
    	cin.ignore();
    	cout << "Press Enter to Exit...";
    	cin.get();
    }
    
    void displayBoard(const vector<char>& board)
    {
    	cout << "\n\n" << board[0] << " | " << board[1] << " | " << board[2] << endl;
    	cout << "---------" << endl;
    	cout << board[3] << " | " << board[4] << " | " << board[5] << endl;
    	cout << "---------" << endl;
    	cout << board[6] << " | " << board[7] << " | " << board[8] << endl;
    
    }
    
    char choosePiece()
    {
    	cout << "\n\nPiece 1 = X" << endl;
    	cout << "Piece 2 = O" << endl;
    
    	char piece;
    
    	cout << "Enter a number to choose your piece [1-2]: " << endl;
    	cin >> piece;
    
    	if (piece == '1')
    	{
    		return X;
    	}
    	else {
    		return O;
    	}
    }
    
    char winner(const vector<char>& board)
    {
    	// multi-dimensional array that holds all possible winning rows
    	int WINNING_ROWS[8][3] = { {0, 1, 2},
    							   {3, 4, 5},
    							   {6, 7, 8},
    							   {0, 3, 6},
    							   {1, 4, 7},
    							   {2, 5, 8},
    							   {0, 4, 8},
    							   {2, 4, 6} };
    
    	const int TOTAL_ROWS = 8; // there are only 8 possible winning rows
    
    	// check to see if any winning row has three values that are the same and not empty
    	// then we have a winner and return the value of that row ( either X or O )
    	for (int i = 0; i < TOTAL_ROWS; i++)
    	{
    		if (board[WINNING_ROWS[i][0]] != EMPTY &&
    			board[WINNING_ROWS[i][0]] == board[WINNING_ROWS[i][1]] &&
    			board[WINNING_ROWS[i][1]] == board[WINNING_ROWS[i][2]])
    			{
    				return board[WINNING_ROWS[i][0]];
    			}
    	}
    
    	// since no body has won, check for a tie, that is there are no empty squares left
    	const int NUM_OF_POSITIONS = 9; // number of square in the game board
    	int emptyPositions = 0;
    
    	for (int i = 0; i < NUM_OF_POSITIONS; i++)
    	{
    		if (board[i] == EMPTY)
    		{
    			emptyPositions++;
    		}
    	}
    
    	// if there are no empty positions left in the board then the game is a tie
    	if (emptyPositions == 0)
    	{
    		return TIE;
    	}
    	else {
    		return NO_ONE; // it's neither a tie nor any player has won the game yet, the game is still remaining
    	}
    }
    
    char firstMove(const char& player1, const char& player2)
    {
    	char move;
    
    	cout << "\n\nWho will make the first move? " << player1 << " or " << player2 << " ?" << endl;
    	cout << "Enter "<< player1 << " or " << player2 << " : ";
    	cin >> move;
    
    
    
    	return toupper(move);
    }
    
    int playerOneMove(const vector<char>& board, const char player1)
    {
    	int move;
    	bool done = false;
    	while (done != true)
    	{
    		cout << "\n" << player1 << " has to make the move" << endl;
    		cout << "Where will you move?" << " (0-" << board.size() - 1 << "): ";
    
    		// Proceed only if input succeeds
    		if (cin >> move)
    		{
    			// if the move is less than zero or move is greater than 8 then print error message
    			// if move is 0 then it is not less than zero so no error, same goes for when move is 8
    			if (move < 0 || move > 8)
    			{
    				cout << "\n!!! No such move exists - try again !!!" << endl;
    				displayBoard(board);
    			}
    			// check if that move is legal, that is it is not filled with X or O
    			else if (board[move] != EMPTY)
    			{
    				cout << "\n!!! Place is taken - choose another position !!!" << endl;
    				displayBoard(board);
    			}
    			// if none of the if...else statements above are executed
    			// then initialize done with true value so that the for loop could execute
    			else
    			{
    				done = true;
    			}
    		}
    		else
    		{
    			cout << "\n!!! WRONG INPUT !!!" << endl;
    			cin.clear();
    			cin.ignore();
    		}
    
    	}
    	return move;
    }
    
    int playerTwoMove(const vector<char>& board, const char player2)
    {
    	int move;
    	bool done = false;
    	while ( done != true )
    	{
    		cout << "\n" << player2 << " has to make the move" << endl;
    		cout << "Where will you move?" << " (0-" << board.size() - 1 << "): ";
    		
    		// Proceed only if input succeeds
    		if (cin >> move)
    		{
    		
    			// if the move is less than zero or move is greater than 8 then print error message
    			// if move is 0 then it is not less than zero so no error, same goes for when move is 8
    			if (move < 0 || move > 8)
    			{
    				cout << "\n!!! No such move exists - try again !!!" << endl;
    				displayBoard(board);
    			}
    			// check if that move is legal, that is it is not filled with X or O
    			else if (board[move] != EMPTY)
    			{
    				cout << "\n!!! Place is taken - choose another position !!!" << endl;
    				displayBoard(board);
    			}
    			// if none of the if...else statements above are executed
    			// then initialize done with true value so that the for loop could execute
    			else
    			{
    				done = true;
    			}
    		}
    		else
    		{
    			cout << "\n!!! WRONG INPUT !!!" << endl;
    			cin.clear();
    			cin.ignore();
    		}
    	}
    	return move;
    }

    @matsp: Is this what you meant ? It works correctly though, but still let me know that is it appropriate ?

    Thanks everyone

  6. #6
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    move > 8
    what this magic value is doing here?
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  7. #7
    Registered User
    Join Date
    Nov 2007
    Posts
    164
    whats the definition of magic value ????

  8. #8
    C++ Witch laserlight's Avatar
    Join Date
    Oct 2003
    Location
    Singapore
    Posts
    28,413
    A magic number is "some non-obvious constant whose value is significant to the operation of a program and that is inserted inconspicuously in-line".
    Quote Originally Posted by Bjarne Stroustrup (2000-10-14)
    I get maybe two dozen requests for help with some sort of programming or design problem every day. Most have more sense than to send me hundreds of lines of code. If they do, I ask them to find the smallest example that exhibits the problem and send me that. Mostly, they then find the error themselves. "Finding the smallest program that demonstrates the error" is a powerful debugging tool.
    Look up a C++ Reference and learn How To Ask Questions The Smart Way

  9. #9
    Registered User
    Join Date
    Nov 2007
    Posts
    164
    If the move is higher than 8 it should print WRONG Input

    If the move is 8, then move > 8 is false

  10. #10
    Kernel hacker
    Join Date
    Jul 2007
    Location
    Farncombe, Surrey, England
    Posts
    15,677
    Quote Originally Posted by manzoor View Post
    If the move is higher than 8 it should print WRONG Input

    If the move is 8, then move > 8 is false
    What Laserlight is trying to say is that 8 should not be in your code - it should be a named constant, so that when you decide to change the size of your board, that you don't have to scan the whole source for the number 8 and determine if that is part of your range check for the board size or some other 8 value.

    Oh, and this:
    Code:
    const int TOTAL_ROWS = 8; // there are only 8 possible winning rows
    can be done by:
    const int TOTAL_ROWS = sizeof(WINNING_ROWS) / sizeof(WINNING_ROWS[0]);
    [/code]
    Altnernatively, use TOTAL_ROWS to define the size of the WINING_ROWS (which isn't really ROWS, is it?)


    --
    Mats
    Compilers can produce warnings - make the compiler programmers happy: Use them!
    Please don't PM me for help - and no, I don't do help over instant messengers.

  11. #11
    Ethernal Noob
    Join Date
    Nov 2001
    Posts
    1,901
    Quote Originally Posted by manzoor View Post
    whats the definition of magic value ????
    Magic numbers magically make you forget why you put them there in the first place

  12. #12
    Officially An Architect brewbuck's Avatar
    Join Date
    Mar 2007
    Location
    Portland, OR
    Posts
    7,396
    There is no such thing as an "infinite loop due to incorrect input." There is, however, an infinite loop due to an incorrect program.
    Code:
    //try
    //{
    	if (a) do { f( b); } while(1);
    	else   do { f(!b); } while(1);
    //}

  13. #13
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    If the move is higher than 8 it should print WRONG Input
    before it you are asking to enter value between 0 and board.size() - 1

    then check it to be in range [0,8] - just great...

    Someone reading this code will ask himself a question - it is bug? is it feature, does the board always has to have size of 9? does this 8 have something to do with the
    const int TOTAL_ROWS = 8; or maybe
    with const int NUM_OF_POSITIONS = 9;

    3 lines of code make wonders to the reader... Great code...
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Incomprehensible Infinite Loop
    By cunnus88 in forum C++ Programming
    Replies: 4
    Last Post: 02-08-2006, 10:05 AM
  2. Switch statement = infinite loop
    By Lucid003 in forum C++ Programming
    Replies: 10
    Last Post: 10-10-2005, 12:46 AM
  3. stays in loop, but it's not an infinite loop (C++)
    By Berticus in forum C++ Programming
    Replies: 8
    Last Post: 07-19-2005, 11:17 AM
  4. Incorrect Input
    By CeeCee in forum C Programming
    Replies: 1
    Last Post: 11-26-2001, 12:25 PM
  5. infinite loop
    By sballew in forum C Programming
    Replies: 6
    Last Post: 09-22-2001, 11:04 AM