Problems with reading char input and with a loop counter - c++

Ok so I am having a major issue here, and after spending two days on this, I can not find out why it is not working as I think it should.
First problem: I have a function to see if the player wished to play again by inputting a y or n. If they press n, it terminates as it should, but if they press Y or y it just asks them again if they want to play again, until any other char other than y is pushed that is.
My second issue, and the most annoying, is the loop counter I am using to determine if the char they entered as a guess was used or not in the word (hangman game). It worked before, after I made some minor changes, it no longer works as intended, and the butt of it is that I didn't mess with that code at all, it was elsewhere. Essentially, the loop counter is reset to 0 every time the loop encounters the user guess within the word, but if the counter equals the length of the word, that means that the user guess was not found, and it should set the display value to plus one. However, all it does NOW is stay at zero all the time, even if the user enters an incorrect guess, which should increment the display value by one, it remains at zero. I have spent two days trying to get JUST this part to work, and it WAS working yesterday, but not today, and I can use another set of eyes on it to see if I overlooked something!
void playHangman(string wordArray[], bool usedWords[])
{
string secretWord;
unsigned seed = time(0);
srand(seed);
int wordChoice = (rand()%20);
int counter = 0;
int display = 0;
bool winner = false;
int wordLength = secretWord.length();
int count;
char again;
do
{
while(usedWords[wordChoice])
{
if(wordChoice == 19)
wordChoice = 0;
else if(counter == 20)
{
for(int i = 0; i < SIZE; i++)
usedWords[i] = false;
wordChoice = (rand()%20);
counter = 0;
}
wordChoice++;
counter++;
}
secretWord = wordArray[wordChoice];
const char *word = new char [secretWord.length()];
word = secretWord.c_str();
char *userPrompt = new char [secretWord.length()];
for(int i = 0; i < secretWord.length(); i++)
userPrompt[i] = '_';
userPrompt[secretWord.length()] = '\0';
char userGuess = '\n';
while(!winner)
{
count = 0;
for(int i = 0; i < secretWord.length(); i++)
cout << userPrompt[i] << " ";
cout << "\n" << endl;
displayGallows(display);
if(display == 6)
{
cout << "Sorry, you lost!" << endl;
break;
}
cout << "Enter a letter: ";
cin >> userGuess;
cin.ignore();
for(int i = 0; i < secretWord.length(); i++)
{
if(word[i] == userGuess)
{
userPrompt[i] = userGuess;
count = 0;
}
else if(count == (wordLength - 1))
display++;
count++;
}
winner = checkWin(word, userPrompt, display, secretWord);
}
again = playAgain();
}while(again == 'Y' || again =='y');
}
char playAgain()
{
char playAgain;
cout << "Would you like to play again? Enter y or n: ";
cin >> playAgain;
return playAgain;
}

There are really two questions:
Why doesn't it restart a game? Answer: because the program thinks that the game was successfully played. You set up your variables in front of the loop and you don't reset them to play another game. Recommendation: create a function which actually plays the game and just call it from the outer loop. Play the game in that function.
Why doesn't it increment count? Dunno. Why you think count always stays at 0? However, it seems the condition count == (wordLength - 1) is unlikely to every become true because wordLength is set to the size of secretWord when secretWord happens to be empty (i.e. wordLength is set to 0) and never changed afterwards.

Asking to play again may be due to not resetting variable "winner". Doing as follows may correct it.
do
{
winner = false; //set to false at each iteration
while(usedWords[wordChoice])
{
if(wordChoice == 19)
wordChoice = 0;
else if(counter == 20)

Related

Visual Studio shows warning C6330: 'char' passed as _Param_(1) when 'unsigned char' is required in call to 'isdigit'. when I try to build

This is only a small part from my code. What I'm trying to do is writing at the end of the file (add record) which in this case is "books.txt" that already has 40 records. But when I debug, it would still prompt the user to enter isbn code but after entering, (process 3296) exited with code 3. came out. Which part am I doing wrong? The counter() function is to count how many records I already have in my file. And I'm also using array of struct to store my records.
int add_record(DATA book[])
{
int count = counter();
system("CLS");
cout << "\t\t\t\t\t\t\t\t : :Add Book Record: :\n\n";
bool cont;
ofstream outfile("books.txt", ios::app);
if (outfile.is_open() && !outfile.eof())
{
do
{
cont = true;
cout << "ISBN Code: ";
cin.getline(book[++count].isbn_code, 14, '\n');
//cin.ignore(numeric_limits<streamsize>::max(), '\n');
int length = strlen(book[++count].isbn_code);
for (int i = 0; i <= length; i++)
{
if (!isdigit(book[++count].isbn_code[i]))
{
cont = false;
cout << "Your input is invalid. Enter again.\n";
break;
}
}
} while (cont == false);
do
{
cont = true;
cout << "Author: ";
cin.getline(book[++count].author, 50, '\n');
int length = strlen(book[++count].author);
for (int i = 0; i <= length; i++)
{
if (isdigit(book[++count].author[i]))
{
cont = false;
cout << "Your input is invalid. Enter again.\n";
break;
}
}
} while (cont == false);
outfile << book[++count].isbn_code << "," << book[++count].author ;
outfile.close();
}
else
cout << "File is not open\n";
return 0;
}
Yes, the error message is completely correct. This is a rare case where using a cast is the correct thing to do
if (isdigit(static_cast<unsigned char>(book[++count].author[i])))
Reference, https://en.cppreference.com/w/cpp/string/byte/isdigit
But this has nothing to do with your crash which is caused by other errors. For instance
cin.getline(book[++count].isbn_code, 14, '\n');
//cin.ignore(numeric_limits<streamsize>::max(), '\n');
int length = strlen(book[++count].isbn_code);
You definitely don't want to increment count twice. I would guess the correct code is
cin.getline(book[count].isbn_code, 14, '\n');
int length = strlen(book[count].isbn_code);
and to increment count once later in your loop.
Remember ++count is not the same as count + 1. The first increments the count variable, that is it changes the value of the count variable, but count + 1 just adds one to count and does not change the value of the count variable.
This is also wrong
for (int i = 0; i <= length; i++)
In C++ string indexes start at zero and go upto the length of the string minus one, so the correct code is
for (int i = 0; i < length; i++)
Also not part of your question but X can be a legal character in an ISBN.

How do I make a real-time updating grid in c++

So I'm making a sudoku solver to kind of test myself, and I have seem to hit a wall.
I'm trying to get the user to input values into a grid, and it'll automatically update every couple of seconds to see the next value they put in the grid.
I don't know how to get the user input into the grid itself.
Here is my code for the grid itself.
void draw()
{
int given;
cout << endl;
for (int i = 0; i < 13; i++)
{
for (int j = 0; j <= 9; j++)
{
if (j == 0)
{
cout << "|";
}
if (j == 3 || j == 6 || j == 9 )
{
cout << "|";
}
if (i == 0 || i == 4 || i == 8 || i == 12)
{
cout << "#";
}
else
{
cout << " ";
}
}
cout << endl;
}
}
To get this to refresh, I have this loop.
while (gameOver != TRUE)
{
system("cls");
draw();
cout << "\nEnter the next given number, or 0 for a blank space: ";
Sleep(600);
}
So I need help getting the user input value to both
Display on the grid
Save in any way (I think an array might work best?)
Thanks.
I personally think that the easiest way to visualize (and store) the values would be in a two-dimensional array.
You can declare and n * m array like this :
int x[n][m];
Then access elements (i,j) like this in your for loop to display it :
x[i][j]
By this line I guess you're programming on Windows:
system("cls");
So my answer will be based on that and utilize a lot of WinAPI.
Normally, you can stick to cin and update the grid after user presses Enter. But since you want a real-time display refresh, this doesn't seem optimal. You have conio.h on Windows so go for it:
#include <conio.h>
...
char ch;
while (true) {
while (!kbhit()); // Wait for user input
ch = getch();
switch (ch) {
// Process input here.
}
}

Stuck with an infinite loop and whitespaces detection c++

This is the question that needs to be implemented:
Write a C++ program that stops reading a line of text when a period is
entered and displays the sentence with correct spacing and capitalization. For this program, correct spacing means only one space between words, and all letters should be lowercase, except the first letter. For example, if the user enters the text "i am going to Go TO THe moVies.", the displayed sentence should be "I am going to go to the movies."
I have written my piece of code which looks like this:
// Processing a sentence and verifying if it is grammatically correct or not (spacing and capitalization)
//#include <stdio.h>
//#include <conio.h>
#include <iostream>
#include <string>
using namespace std;
int main()
{
string sentence;
cout << "Enter the sentence: ";
getline(cin, sentence);
int len = sentence.length();
// Dealing with capitalizations
for (int j = 0; j <= len; j++)
{
if (islower(sentence[0]))
sentence[0] = toupper(sentence[0]);
if(j>0)
if(isupper(sentence[j]))
sentence[j] = tolower(sentence[j]);
}
int space = 0;
do
{
for (int k = 0; k <= len; k++)
{
if(isspace(sentence[k]))
{
cout << k << endl;
int n = k+1;
if(sentence[n] == ' ' && n <=len)
{
space++;
cout << space <<endl;
n++;
cout << n <<endl;
}
if(space!= 0)
sentence.erase(k,space);
cout << sentence <<endl;
}
}
len = sentence.length();
//cout << len <<endl;
} while (space != 0);
}
With this I was able to deal with capitalization issue but problem occurs when I try to check for more than one whitespace between two words. In the do loop I am somehow stuck in an infinite loop.
Like when I try and print the length of the string (len/len1) in the first line inside do-while loop, it keeps on running in an infinite loop. Similarly, when I try and print the value of k after the for loop, it again goes into infinite loop. I think it has to do with my use of do-while loop, but I am not able to get my head around it.
This is the output that I am receiving.
there are a few different issues with this code, but i believe that the code below addresses them. hopefully this code is readable enough that you can learn a few techniques. for example, no need to capitalize the first letter inside the loop, do it once and be done with it.
the usual problem with infinite loops is that the loop termination condition is never met--ensure that it will be met no matter what happens in the loop.
#include <iostream>
#include <string>
using namespace std;
int main() {
string sentence;
cout << "Enter the sentence: ";
getline(cin, sentence);
int len = sentence.find(".", 0) + 1; // up to and including the period
// Dealing with capitalizations
if (islower(sentence[0]))
sentence[0] = toupper(sentence[0]);
for (int j = 1; j < len; j++)
if(isupper(sentence[j]))
sentence[j] = tolower(sentence[j]);
// eliminate duplicate whitespace
for (int i = 0; i < len; i++)
if (isspace(sentence[i]))
// check length first, i + 1 as index could overflow buffer
while (i < len && isspace(sentence[i + 1])) {
sentence.erase(i + 1, 1);
len--; // ensure sentence decreases in length
}
cout << sentence.substr(0, len) << endl;
}
Here goes
std::string sentence;
std::string new_sentence;
std::cout << "Enter the sentence: ";
std::getline(std::cin, sentence);
bool do_write = false; // Looking for first non-space character
bool first_char = true;
// Loop to end of string or .
for (unsiged int i = 0; i < sentence.length() && sentence[i] != '.'; ++i) {
if (sentence[i] != ' ') { // Not space - good - write it
do_write = true;
}
if (do_write) {
new_sentence += (first_char ? toupper(sentence[i]) : tolower(sentence[i]);
first_char = false;
}
if (sentence[i] == ' ') {
do_write = false; // No more spaces please
}
}
if (i < sentence.length()) { // Add dot if required
new_sentence += '.';
}

jumping outside loop in a specific case

I am writing a code that, for one or several lines of strings, find if the overall input has only "cool" (it's first middle and last string are the same) lines, only "uncool" lines or a mix of both.
The problem I'm having is whenever I input an even number the while loop terminates. Debugging I found that, just before jumping out n gets value 0 but I don't understand how this would make the loop end.
This is the code:
#include <iostream>
using namespace std;
int main () {
// Bool has control if we have found a cool line/non-cool line
bool cool = false;
bool uncool = false;
int n; //lenght of input
while (cin >> n) {
if (cool and uncool) break; // we have found one of each so we know it is a mixed input
else if (n%2 == 0) uncool = true; // if the lenght is even there is no middle string
else {
// we are trying to see if the middle and last string are equal to the first
string comparing_string;
cin >> comparing_string;
string rest_of_sequence;
bool this_is_cool = true;
for (int i = n-2; i >= 0; i--) { // we input the rest of strings and compare them to the first
cin >> rest_of_sequence;
if ((i == n/2 or i == 0) and rest_of_sequence != comparing_string) this_is_cool = false;
}
if (this_is_cool) cool = true;
else uncool = true;
}
}
if (cool and uncool) cout << "both types" << endl;
else if (cool and not uncool) cout << "all cool" << endl;
else if (uncool and not cool) cout << "none cool" << endl;
}
Any help is appreciated! I'm currently in first year of uni and always open to recommended books/webpages/videos to continue learning :)
The problem was that I thought the program would just ignore input that wasn't an integer in the while loop, but it doesn't.
Now the code is correct:
else if (n%2 == 0) {// if the lenght is even there is no middle string
uncool = true;
string just_passing_input;
for (int i = n; i > 0; i--) cin >> just_passing_input;
}
Thanks for the helpful feedback, I shall now continue learning.

A simple C++ While loop not working

I have a simple while loop i'm trying to implement but for the life of me can't figure out what I'm missing. I have currentuser initialized at the top to -1
while(currentuser = -1){
cout << "Enter user ID: ";
cin >> id;
currentuser = search(a, length, id);
}
My search function is this:
int search (User a[ ], int length, string userID){
User u;
string tempid;
int templegnth; //I ignore length for now as I will use it later
for(int i=0; i<50; i++){
tempid = a[i].getID();
templegnth = tempid.length();
if((tempid == userID)){
return i;
}
}
return -1;
}
I know its something very simple but the answer escapes me right now.
The = (assignment) operator is not the same as the == (equality) operator.
The line :
while(currentuser = -1){
first assigns -1 to currentuser, and then checks if currentuser has a non-zero value. This will always be the case (-1 != 0), so the loop will never end.
You likely meant this instead :
while(currentuser == -1){
which compares currentuser to -1, and continues the loop as long as that comparison is true.
You need to change:
while(currentuser = -1){
to be:
while(currentuser == -1){
Currently you are assigning currentuser to -1 every time your loop runs, rather than checking if it is still assigned to that value.
Try == -1 instead of = -1
You've got the answers but here is a tip on how to avoid it in the future.
Always try to use
while(-1 == currentuser){
std::cout << "Enter user ID: ";
std::cin >> id;
currentuser = search(a, length, id);
}
as this way
while(-1 = currentuser){
;
}
will be thrown out by the compiler
Even with the = changed to ==, the loop still has problems.
while(currentuser == -1){
std::cout << "Enter user ID: ";
std::cin >> id;
currentuser = search(a, length, id);
}
Typing an EOT (control-D on a Linux box, control-Z? on windows) will raise std::cin's end of file condition. The value of id won't be changed, and the lookup will presumably keep on returning -1. The result is an infinite loop with lots of spew to std::cout.
One way to fix this is to break out of the loop when the std::cin >> id; fails. For example, if (! (std::cin >> id)) break;
Whenever I use a while loop and a boolean, I try to make sure it only runs if it is above or is 50 but instead whenever I execute a cout with the while and int, the outcome is a literal mess, its like the while loop executes a lot more than it should. Eg.
int Buses;
int People;
cin >> People;
while(People >= 50){
Buses += 1;
People -= 50;
};
cout << Buses << endl;
and when I input 757, my result was 32782.
Even by subtracting the int value by 32767, the values sort of fix itself but not the higher numbers, 99 is 1, 101 is 2 but c++ says that 300 is 3 although it is meant to be 6.
(My solution I found: I had to declare the Person and Buses variable with a 0 because the value was different without the starting 0.)
This is the fixed code:
int Buses = 0;
int People = 0;
cin >> People;
while(People >= 50){
Buses += 1;
People -= 50;
};
cout << Buses << endl;