Thread: infinite loop due to incorrect input

1. 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;

}

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. Why are you using a for loop? You can just use a while loop:

Code:
`while ( done != true )`
And:

Code:
`bool checkInput = cin >> move;`

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. 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

4. 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. 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;

}

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. move > 8
what this magic value is doing here?

7. whats the definition of magic value ????

8. 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".

9. If the move is higher than 8 it should print WRONG Input

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

10. Originally Posted by manzoor
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

11. Originally Posted by manzoor
whats the definition of magic value ????
Magic numbers magically make you forget why you put them there in the first place

12. There is no such thing as an "infinite loop due to incorrect input." There is, however, an infinite loop due to an incorrect program.

13. 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...

Popular pages Recent additions