Sudoku input program skipping a prompt - c++

I wrote a program for my computer science class that validates and solves sudoku puzzles from .txt files, but I wanted to take it one step further and write a program that made it easy to input and sudoku game. I'm sure you can figure out the format of the files based on this code. My only problem is that the last cin gets skipped, and that option is important to me. Any insight will be appreciated!!
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
struct s {
s();
~s() {/*zzzz*/}
void show_grid();
void set (int &r, int &c, int &v) {g[r][c] = v;}
private:
int g[9][9];
};
//************************************************************************
void s::show_grid() {
//print game out to check it
cout << " | ------------------------------- |" << endl;
for (int k=0; k<81; k++) {
if (k%3 == 0)
cout << " |";
cout << " " << g[k/9][k%9];
if (k%9 == 8) {
cout << " |" << endl;
if ((k/9)%3 == 2)
cout << " | ------------------------------- |" << endl;
}
}
cout << endl;
}
//************************************************************************
s::s() {
//initialize all elements to zero
for (int i=0; i<9; i++) {
for (int j=0; j<9; j++) {
g[i][j] = 0;
}
}
}
//************************************************************************
void create_name (string &name) {
//append .txt extension LIKE IT OR NOT
string ext = name;
ext.erase(ext.begin(), ext.end() - 4);
if (ext.compare(".txt")!=0)
name.append(".txt");
}
//************************************************************************
int main () {
s g;
string name;
string yon("");
int count = 0;
int row, col, val, rcv;
ofstream os;
cout << "Enter game file name: ";
cin >> name;
create_name(name);
//open and do typical checks
os.open(name.c_str());
if (os.fail()) {
cerr << "Could not create " << name << ". Waaaah waaaaaaaaaah...\n\n";
return 0;
}
//useful output (hopefully)
cout << "Enter grid coordinates and value as a 3-digit number,\n"
<< "from left to right, row by row.\n"
<< "(e.g. 2 in first box would be 112)\n";
//take input as one int, to be user friendly
while (cin >> rcv && count < 81) {
row = (rcv / 100) - 1;
col = ((rcv / 10) % 10) - 1;
val = rcv % 10;
os << row << " " << col << " " << val << endl;
g.set (row, col, val);
count++;
}
os.close();
//From here down is broken, but it still compiles, runs, and works
cout << "Show grid input(y/n)?\n";
cin >> yon;
if (yon.compare("y")==0)
g.show_grid();
else if (yon.compare("n")==0)
cout << "Peace!\n";
return 0;
}

The problem is here:
while (cin >> rcv && count < 81)
Consider what happens when count==81: First, rcv will be input from cin, and only then the condition count < 81 will be evaluated to false. The loop will stop, and the value of rcv will be ignored. So effectively you read one input too many.
You should change the order of evaluation, so that count is checked first:
while (count < 81 && cin >> rcv)
Edit:
According to your comment above you are actually expecting to read less than 81 values. In that case, I recommend having the user input a special value (for example, 0) to terminate the loop. You'd just need to add if (rcv==0) break;. If you just input an invalid value as you are apparently doing, the cin stream will be put in a failed state and further input will not succeed.

Try something like:
//useful output (hopefully)
cout << "Enter grid coordinates and value as a 3-digit number,\n"
<< "from left to right, row by row.\n"
<< "(e.g. 2 in first box would be 112)\n"
<< "or Z to end the loop\n"; // 1
//take input as one int, to be user friendly
while (count < 81 && cin >> rcv ) { // 2
row = (rcv / 100) - 1;
col = ((rcv / 10) % 10) - 1;
val = rcv % 10;
os << row << " " << col << " " << val << endl;
g.set (row, col, val);
count++;
}
if(!std::cin) { // 3
std::cin.clear();
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
1) Let the user know that he can enter in invalid char. It doesn't have to be Z, actually any non-numeric char will work.
2) Fix off-by-one error in the order of the &&.
3) If std::cin is in error state, clear the error and ignore the Z.

cin >> yon
still actually reads in a variable, it just reads in the variable that the while loop found to be false. When the while loop condition returns false rcv is ignored, so the number remains in the input stream waiting for the next cin statement. When yon is called that number meant for rcv is read into yon, giving you some strange errors.
it would be better to use interjay's method:
while (count < 81 && cin >> rcv)

Related

Why is one of the while loops not being executed (C++)?

I am using the book "Programming : Principles and Practice Using C++(Second Edition)" by "Bjarne Stroustrup". I am stuck in the last exercise question of the chapter 4. I have tried to look up the solutions for this particular question but I am not getting the solution for the Second Edition.
There are two extensions for this question and each one requires a while-loop. Only the first while-loop is getting executed and it doesn't matter which one I place first.
The question is "Write a program where you first enter a set of name-value pairs. Terminate input with NoName 0. Each and every name entered must be unique."
Extension for the question is "Modify the program so that when you enter the name, corresponding score will be the output."
Extension for the question is "Further modify the program so that when you enter the score, corresponding names will be the output."
int main()
{
cout << "Enter a name and score side-by-side and enter 'NoName 0' when done :\n";
int scores_temp{ 0 };
string names_temp{ 0 };
vector <int> scores;
vector <string> names;
int adder{ 0 };
while (cin >> names_temp >> scores_temp)
{
if (names_temp == "NoName")
{
if (scores_temp == 0)
{
break;
}
}
else
{
for (int i = 0; i < names.size(); i++)
{
if (names_temp == names[i])
{
adder++;
}
}
if (adder == 0)
{
names.push_back(names_temp);
scores.push_back(scores_temp);
}
else
{
cout << "\nYou can't enter the same name twice.\n\n";
break;
}
}
}
for (int j = 0; j < names.size(); j++)
{
cout << names[j] << "\t" << scores[j] << "\n";
}
cout << "Enter the name to get the corresponding score and enter Ctrl+Z when done : \n";
string name_score{ 0 };
int counter{ 0 };
while (cin >> name_score)
{
for (int l = 0; l < names.size(); l++)
{
if (name_score == names[l])
{
cout << "Score of " << names[l] << " is " << scores[l] << ".\n";
}
else
{
counter++;
}
}
if (counter == names.size())
{
cout << "Name not found.\n";
}
counter = 0;
}
cout << "Enter the score to get the corresponding names and enter a character when done : \n";
int score_name{ 0 };
int incrementer{ 0 };
while (cin >> score_name)
{
for (int k = 0; k < scores.size(); k++)
{
if (score_name == scores[k])
{
cout << "Score of " << scores[k] << " was obtained by " << names[k] << ".\n";
}
else
{
incrementer++;
}
}
if (incrementer == scores.size())
{
cout << "Score not found.\n";
}
incrementer = 0;
}
keep_window_open();
return 0;
}
The header file for the program is given by Bjarne himself. The website for the header file is :
http://www.stroustrup.com/Programming/PPP2code/std_lib_facilities.h
There are two extensions for this question and each one requires a while-loop. Only the first while-loop is getting executed and it doesn't matter which one I place first.
while (cin >> name_score)
This first loop continues until cin fails. If cin has already failed, it won't even loop once.
while (cin >> score_name)
Since we only get to this second loop if cin has failed, and this loop won't even loop once if cin fails, the code inside this while loop can never execute.
You either need some way to exit that first while loop without input having to fail, like the NoName 0 does in the very first loop or you need to clear cin's fail flag between these while loops.
See Why would we call cin.clear and cin.ignore() after reading input? for more details.

How do I my Program to stop Replicating if wrong input

My program will repeat output: "You are currently on the 2 floor out of 5
The sum of the codes is: 7 and the product of the codes is: 12
Try again before he catches onto you!"
Based on how many wrong characters are added how can I fix this? I have inserted the cin.clear and cin.ignore but it will repeat the part above.
i.e. if I type wasds it will repeat 5x. Any other notes are also appreciated.
#include <iostream>
#include <ctime>
using namespace std;
int PlayerLevel = 0;
int MaxLevel = 5;
bool GamePlay ()
{
srand(time(NULL));
int PlayerGuessA, PlayerGuessB, PlayerGuessC;
int CodeA = rand() % PlayerLevel + PlayerLevel;
int CodeB = rand() % PlayerLevel + PlayerLevel;
int CodeC = rand() % PlayerLevel + PlayerLevel;
int SumofCodes = CodeA + CodeB + CodeC;
int ProductofCodes = CodeA * CodeB * CodeC;
cout << "You are currently on the " << PlayerLevel << " floor out of 5" << endl;
cout << "The sum of the codes is: " << SumofCodes << " and the product of the codes is: " << ProductofCodes << endl;
cin >> PlayerGuessA >> PlayerGuessB >> PlayerGuessC;
int PlayerProduct = PlayerGuessA * PlayerGuessB * PlayerGuessC;
int PlayerSum = PlayerGuessA + PlayerGuessB + PlayerGuessC;
if (PlayerProduct == ProductofCodes && SumofCodes == PlayerSum) {
cout << "Great Job you got this!!!\n" << endl;
++PlayerLevel;
return true;
}
else
{
cout << "Try again before he catches onto you!\n" << endl;
return false;
}
}
int GameStart()
{
string Introduction = "Welcome to your worst nightmare. You are trapped in a murderer's house. You are on the 5th floor and need to get to the first floor to escape.\n";
string Instructions = "He has each door locked behind a security system that requires a 3 number code to disarm it.\nEnter the codes and move foward. Each level will the code will be harder to figure out.\n";
string PlayerStart;
cout << Introduction << endl;
cout << Instructions << endl;
cout << "Would you like to escape? Yes or No" << endl;
cin >> PlayerStart;
if (!(PlayerStart != "Yes" && PlayerStart != "yes")) {
++PlayerLevel;
}
return 0;
}
int main ()
{
if (PlayerLevel == 0) {
GameStart();
}
while (PlayerLevel <= MaxLevel)
{
bool bLevelComplete = GamePlay();
cin.clear ();
cin.ignore();
}
cout << "You Made it out! Now run before he finds out!" << endl;
return 0;
}
When the type of the input doesn't match the type of the variable that it is being extracted to, cin sets the fail bit. Once this happens, all subsequent reads fail until the stream is reset. The offending characters are still left in the buffer, so that needs to be cleared out as well.
Your usage of cin.clear() and cin.ignore() meant that the fail bit was getting reset, but only one offending character was being removed (cin.ignore() ignores one character by default). This is why you saw the output repeating x times for x erroneous characters.
You could do something like this:
while (PlayerLevel <= MaxLevel)
{
bool bLevelComplete = GamePlay();
if (cin.fail())
{
//Input extraction failed, need to reset stream and clear buffer until newline
cin.clear();
cin.ignore(numeric_limits<streamsize>::max(),'\n');
}
}

cin a char into an int variable to stop a loop

I would like to read numbers into a static array of fixed size 10, but the user can break the loop by entering character E.
Here's my code:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
int myArray[10];
int count = 0;
cout << "Enter upto 10 integers. Enter E to end" << endl;
for (int i = 0; i < 10; i++)
{
cout << "Enter num " << i + 1 << ":";
cin >> myArray[i];
if (myArray[i] != 'E')
{
cout << myArray[i] << endl;
count++;
}
else
{
break;
}
}
cout << count << endl;
system("PAUSE");
return 0;
}
However, I get the following results while entering E:
Enter upto 10 integers. Enter E to end
Enter num 1:5
5
Enter num 2:45
45
Enter num 3:25
25
Enter num 4:2
2
Enter num 5:E
-858993460
Enter num 6:-858993460
Enter num 7:-858993460
Enter num 8:-858993460
Enter num 9:-858993460
Enter num 10:-858993460
10
Press any key to continue . . .
How can I fix this code in the simplest way?
cin fails for parsing character 'E' to int. The solution would be to read string from user check if it is not "E" (it is a string not a single char so you need to use double quotes) and then try to convert string to int. However, this conversion can throw exception (see below).
Easiest solution:
#include <iostream>
#include <cmath>
#include <string> //for std::stoi function
using namespace std;
int main()
{
int myArray[10];
int count = 0;
cout << "Enter upto 10 integers. Enter E to end" << endl;
for (int i = 0; i < 10; i++)
{
cout << "Enter num " << i + 1 << ":";
std::string input;
cin >> input;
if (input != "E")
{
try
{
// convert string to int this can throw see link below
myArray[i] = std::stoi(input);
}
catch (const std::exception& e)
{
std::cout << "This is not int" << std::endl;
}
cout << myArray[i] << endl;
count++;
}
else
{
break;
}
}
cout << count << endl;
system("PAUSE");
return 0;
}
See documentation for std::stoi. It can throw exception so your program will end suddenly (by termination) that is why there is try and catch blocks around it. You will need to handle the case when user puts some garbage values in your string.
Just use:
char myArray[10];
because at the time of taking input console when get character then try to convert char to int which is not possible and store default value in std::cin i.e. 'E' to 0 (default value of int).
Use below code:
#include <iostream>
#include <cmath>
using namespace std;
int main()
{
char myArray[10];
int count = 0;
cout << "Enter upto 10 integers. Enter E to end" << endl;
for (int i = 0; i < 10; i++)
{
cout << "Enter num " << i + 1 << ":";
cin >> myArray[i];
if (myArray[i] == 'E')
{
break;
}
else
{
cout << myArray[i] << endl;
count++;
}
}
exitloop:
cout << count << endl;
system("PAUSE");
return 0;
}
Output:
Enter upto 10 integers. Enter E to end
Enter num 1:1
1
Enter num 2:E
1
sh: 1: PAUSE: not found
If you debug this, you will find all your myArray[i] are -858993460 (=0x CCCC CCCC), which is a value for the uninitialized variables in the stack.
When you put a E to an int variable myArray[i]. std::cin will set the state flag badbit to 1.
Then when you run cin >> myArray[i], it will skip it. In other words, do nothing.
Finally, you will get the result as above.
The problem is that attempting to read E as an int fails, and puts the stream in an error state where it stops reading (which you don't notice because it just doesn't do anything after that) and leaves your array elements uninitialized.
The simplest possible way is to break on any failure to read an integer:
for(int i = 0; i < 10; i++)
{
cout << "Enter num " << i + 1 << ":";
if (cin >> myArray[i])
{
cout << myArray[i] << endl;
count++;
}
else
{
break;
}
}
If you want to check for E specifically, you need to read a string first, and then convert that to an int if it's not E.
As a bonus, you need to handle everything that's neither int nor E, which complicates the code a bit.
Something like this:
int count = 0;
string input;
while (cin >> input && count < 10)
{
if (input == "E")
{
break;
}
istringstream is(input);
if (is >> myArray[count])
{
cout << myArray[count] << endl;
count++;
}
else
{
cout << "Please input an integer, or E to exit." << endl;
}
}

C++ user entry and error handling

I am currently writing a knights tour program and I am trying to think of the best way to handle the problem I am running into. My goal is to prompt the user to enter in several inputs for a starting place on the board. This means that the user needs to be able to type in several numbers which in my opinion, this means I need an empty array that can accept the input. I am coding in C++ and this is what I have so far:
#include <iostream>
#include <iomanip>
using namespace std;
int greeting(){
cout << "Welcome to the Knights Tour! Please, enter your desired starting places." <<
endl << "Enter any numbers 1-64, and type -1 to start." << endl << endl;
int board[8][8] = {{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}
};
for (int row = 0; row < 8; row++){
for(int column=0; column<8; column++){
cout << setw(3) << board[row][column] << " ";
}
cout << endl;
}
cout << endl;
}
int main(){
greeting();
}
I have tried several methods to accept the user input but what I am ultimately trying to do is allow only integer input from 1-64 and allow the user to type -1 to exit the loop.
Thanks for the help!
int position = 0;
std::string line;
do
{
while (std::cout << "Select position 1-64, or type -1 to exit\n" &&
std::getline(std::cin, line))
{
std::istringstream iss(line);
position = 0;
if (iss >> position &&
(position == -1 ||
position 1 <= position && position <= 64))
{
char c;
if (!(iss >> c))
break;
std::cerr << "trailing character also found on input line, please try again\n";
}
else
std::cerr << "you entered an invalid position, please try again\n";
}
if (1 <= position && position <= 64)
{
// do/call your position-related work here...
}
} while (position != -1 && std::cin);

vector-related segmentation fault

void offer_help();
bool play_one_game();
int main() {
offer_help();
play_one_game();
}
void offer_help() {
int help_response;
cout << "Need help? (0/1) ";
cin >> help_response;
if (help_response == 1)
cout << "I will generate a pattern of 4 numbers, each in the range 0 through 9.\n Each guess that you enter will be a line containing 4 integers,\n separated by spaces, such as:\n\t 2 4 7 1\n FOr each guess, I will echo back a lost consisting of\n 0's and 1's, with a 1 in a given position meaning that\n you guessed the number, and a zero meaning that you didn't.\n For example, if the actual solution was 2 3 6 1, I'll respond\n\t 1 0 0 1\n See how many guesses it takes you to get the solution!\n\n If you want to give up, type a negative number for one of\n your guesses, and we'll tell you what the pattern was.\n\n";
}
bool play_one_game() {
srand(time(0)); //needed to start randint
vector<int> solution; //vector of 4 randomly generated
//solutions
vector<int> guess; //vector containing user guesses.
vector<int> result;
int guess_input;
for(int i = 0; i < solution.size(); ++i)
solution[i] = randint(10);
int trial_number = 0; //int that shows what guess the user is on
while (play_one_game() == true) {
//ask user for inputs.
cout << "Guess #" << ++trial_number << "? ";
for (int i = 0; i < guess.size(); ++i){
cin >> guess_input;
guess.push_back(guess_input);
}
//outputs error if user inputs a letter.
if (!cin) {
cerr << "Bad input data! Feed me numbers!\n";
return 43;
}
if (cin < 0){
cout << "Too bad! Solution was " << endl;
for(int i = 0; i < result.size(); i++)
cout << (result[i]);
}
//determines if user correctly guessed any of the
//numbers and tells the user which is correct.
for (int i = 0; i < result.size(); i++) {
if (guess[i]==solution[i])
cout << 1 << " ";
else if (guess[i]!=solution[i])
cout << 0 << " ";
}
cout << endl;
// playagain();
cout << endl << "Play again (0/1)? ";
int replay;
cin >> replay;
if (replay == 0) {
play_one_game() == false;
return 5;
}
else if (replay == 1)
play_one_game() == true;
else {
cerr << "wat?\n";
return 10;
}
}
}
This is designed to allow a player to guess a pattern of random numbers.
No idea why I am getting a segmentation fault. The program is supposed to call the offer_help function, then the play_one_game function within main function. Then it should ask the player whether he wants to play again. If no, then bool play_one_game should be set to false and it should exit.
This is related to the play_one_game bool function.
You're getting a segmentation fault, because you end up in an endless recursion in the following line:
while (play_one_game() == true) {
play_one_game will call play_one_game in this line, and this will call play_one_game in the same line again. This will result in a stack overflow at last.
Better use some bool keepPlaying; and while(keepPlaying) instead.
EDIT: Well, this is a little bit more than a simple answer, but I like games, so... have a look at the following code:
#include <iostream>
#include <ctime>
#include <cstdlib>
#include <vector>
bool play_one_game();
void offer_help() {
int help_response;
std::cout << "Need help? (0/1) ";
std::cin >> help_response;
if (help_response == 1)
std::cout << "I will generate a pattern of 4 numbers, each in the range 0 through 9.\n"
"Each guess that you enter will be a line containing 4 integers,\n"
"separated by spaces, such as:\n"
"\t 2 4 7 1\n"
"For each guess, I will echo back a lost consisting of\n"
"0's and 1's, with a 1 in a given position meaning that\n"
"you guessed the number, and a zero meaning that you didn't.\n"
"For example, if the actual solution was 2 3 6 1, I'll respond\n"
"\t 1 0 0 1\n"
"See how many guesses it takes you to get the solution!\n\n"
"If you want to give up, type a negative number for one of\n"
"your guesses, and we'll tell you what the pattern was.\n\n";
}
int main() {
offer_help();
srand(time(0)); // Initialize random numbers with current time as seed
while(play_one_game()); // if play_one_game returns true, play again
}
bool play_one_game() {
std::vector<int> solution(4); // Four solutions for our guessing game
std::vector<int> guess; // User guesses
for(unsigned i = 0; i < solution.size(); ++i)
solution[i] = rand() % 10;
int trial_number = 0; //int that shows what guess the user is on
bool keepPlaying = true;
while(keepPlaying){
std::cout << "Guess #" << ++trial_number << "? ";
guess.clear(); // Clear old guesses
for(unsigned i = 0; i < solution.size(); ++i){
int guess_input;
//outputs error if user inputs a letter.
if (!(std::cin >> guess_input)) {
std::cerr << "Bad input data! Feed me numbers!\n";
std::cerr << "Try again!" << std::endl;
std::cin.clear(); // Clear flags
continue;
}
if (guess_input < 0){
std::cout << "Too bad! Solution was " << std::endl;
for(unsigned i = 0; i < solution.size(); i++)
std::cout << (solution[i]);
keepPlaying = false;
break;
}else
guess.push_back(guess_input);
}
if(!keepPlaying)
break;
if(solution.size() != guess.size()){
std::cerr << "Wrong number of guesses, try again!" << std::endl;
continue;
}
//determines if user correctly guessed any of the
//numbers and tells the user which is correct.
bool correct = true;
for (unsigned i = 0; i < solution.size(); i++) {
if (guess[i] == solution[i])
std::cout << 1 << " ";
else{
correct = false;
std::cout << 0 << " ";
}
}
if(correct){
std::cout << "Congratulations - you won!" << std::endl;
break;
}
std::cout << std::endl;
}
int replay = -1;
do{
// Ask user for input until input is 0 or 1
std::cout << std::endl << "Play again (0/1)? ";
std::cin >> replay;
}
while(replay != 0 && replay != 1);
return static_cast<bool>(replay); // return user replay answer (false/true)
}
Try to keep your code as simple as possible. Welcome to SO. And don't expect future answers to be that excessive.
You're never inserting anything into your solution vector. You just declare the vector, and then say:
for(int i = 0; i < solution.size(); ++i)
solution[i] = randint(10);
...which won't do anything since at this point solution.size() == 0. Later, when you iterate over your result vector, you end up accessing invalid elements in your empty solution vector. You also can't assume that the result vector and solution vector are the same size.