jumping outside loop in a specific case - c++

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.

Related

Count the occurrence of numbers in C++?

I just recently created a code in C++ where I have to display the occurrence of numbers from a text file that I made using this code:
using namespace std;
int main()
{
bool isCovered[99] = {};
int number;
// Read each number and mark its corresponding element covered
while (cin.good())
{
cin >> number;
if (number == 0)
{
break;
}
if ((number >= 1) && (number <= 99))
{
isCovered[number - 1] = true;
}
}
// Check if all covered
bool allCovered = true; // Assumes all covered initially
for (int i = 0; i < 99; i++)
if (!isCovered[i])
{
allCovered = false; //Finds one number not covered
break;
}
// Display result
if (allCovered)
cout << "The tickets cover all numbers" << endl;
else
cout << "The tickets don't cover all numbers" << endl;
return 0;
}
It's not displaying a result, is the program too complex, or is it something that I'm missing?
EDIT: Thanks #selbie for the edit to my code, i was able to figure out that it was a user input but when i put in a zero for the final input. It displays the messages "The tickets don't cover all numbers", why is that?
The bug, if any, is here:
cin >> number;
while (number != 0)
{
isCovered[number - 1] = true;
cin >> number;
}
Two possible issues:
If reading from a redirected file, there's no detection of an end-of-file condition. Such would be the case if the program was invoked as program.exe < input.txt and the input.txt did not contain a 0. Without checking for eof, the program will hang when reading from an input file redirection.
Further, there's nothing to guard against bad input. i.e. numbers outside the range of [1..99]. Without guarding against out of range numbers, undefined behavior will get introduced. Or more likely, the stack will get trashed as a result of inserting into a memory address out of range.
The easy fix is this:
while (cin.good())
{
cin >> number;
if (number == 0)
{
break;
}
if ((number >= 1) && (number <= 99))
{
isCovered[number - 1] = true;
}
}

Why isn't the program outputting true regardless of case?

My assignments requires me to keep accepting input from the user and output whether or not it is a palindrome until the word DONE is inputed.
Also, words like Bob must have an output of true because we must disregard case (upper/lower.)
This is my first time using C++.
#include <iostream>
#include <string>
using namespace std;
int main()
{
string wordInput;
while (wordInput != "DONE")
{
cout << "Please enter a word: ";
cin >> wordInput;
int wordLength = wordInput.length();
int wordHalf = (wordLength / 2);
bool flag = false;
for (int i = 0; i <wordHalf; i++)
{
if (tolower((wordInput[i]) == tolower(wordInput[wordLength-1-i])))
{
flag = true;
}
else
{
flag = false;
break;
}
}
if (flag == true)
{
cout << "true"<<endl;
}
else
{
cout << "false"<<endl;
}
}
return 0;
}
It might have something to do with 'wordInput' being declared twice, once right before the while loop and once within it. It is mixing up what the while loops condition is looking at.
Your issue with words not being correctly identified comes from this line:
if(tolower((wordInput[i]) == tolower(wordInput[wordLength-1-i])))
If you look carefully, you set the parentheses incorrectly. Try this instead:
if(tolower(wordInput[i]) == tolower(wordInput[wordLength-1-i]))

I'm having difficulty with my do while loop. It only executes once

The battleship program I wrote is supposed to loop a infinite amount of times until a condition is met. However it stops after the first execution. What is the matter with my loop? The code runs, however towards the end it outputs game over twice when its not supposed to. There are still more ships remaining in the game.
#include<iostream>
#include<fstream>
#include<string>
#include<cmath>
using namespace std;
bool FleetSunk();
void Fire(int&, int&, char&);
char ocean[25][25];
int main()
{
int x;
int y;
char spot;
ifstream input;
input.open("ocean.txt");
for(x=0;x<25;x++)
{
for(y=0;y<25;y++)
{
input >> ocean[x][y];
}
}
FleetSunk == false;
do
{
cout << "Please input x coordinate: ";
cin >> x;
cout << endl << "Please input y coordinate: ";
cin >> y;
cout<< endl;
Fire(x,y,spot);
FleetSunk();
}while(FleetSunk() == false);
}
void Fire(int& x, int&y, char&spot)
{
spot = ocean[x][y];
if(spot == '#')
{
cout << "You Have hit a ship"<< endl;
ocean[x][y] = 'H';
}
else if(spot == 'H')
{
cout << "HIT AGAIN" << endl;
}
else if(spot == '-')
{
cout << "MISS" << endl;
}
}
bool FleetSunk()
{
int m;
int n;
for(m=0;m < 25; m++)
{
for(n=0;n<25;n++)
{
if(ocean[m][n] == '#')
{
cout << "You still have ships remaining" << endl;
}
else
{
cout<< "You have hit all the ships. GAME OVER!" << endl;
return true;
}
}
}
}
Your FleetSunk function has two problems. One should have been a compiler warning, and one is a logical problem.
Firstly, not all paths in the function return a value... Technically. Although in your case that's not quite true because of the logic problem. Let me be more specific: If your entire board is populated with '#', and no shots are taken, then the function behaviour is undefined. It completes the loop and then does not return a value.
So now let's do the logic. You cannot know whether there are any un-hit ship locations until you have examined the entire board. That means you cannot exit from your inner loop in the way you are doing. How about instead you return false if you encounter an "alive" position, and return true at the end of the function (which is only reached if you never encounter an "alive" position).
bool FleetSunk()
{
for( int m = 0; m < 25; m++ )
{
for( int n = 0; n < 25; n++ )
{
if( ocean[m][n] == '#' ) return false;
}
}
return true;
}
See in the comments under your question for other suggestions related to how you are calling FleetSunk in your loop. I also recommend (as evident in my code example) that you don't write stuff to cout in a function that is testing for some condition. It's the responsibility of the caller to do that, not the function itself.
Finally, I would just like to say that the line FleetSunk == false; above your loop really does not do what you might think. That will take the function pointer, convert it to boolean and compare it with false. It's a crazy thing to do, and also useless because the resulting value isn't used for anything. Just delete that line.

Problems with reading char input and with a loop counter

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)

Palindrome tester has logic flaws

This is just a basic palindrome tester for my C++ class, and there appears to be issues.
I already know that I have two separate flaws in here somewhere. At least one, I strongly suspect, is a logic issue. The first problem is that it runs fine the first time through, but when the loop initiates, it doesn't ask for user input to put in a new line to test as a palindrome, it simply retests the old one. The second issue is, I assume, that it is testing spaces, which I base off the fact that it's giving 'hannah' back as good, but 'never even or odd' comes back bad. This one I just don't know how to fix.
#include <iostream>
#include <string>
using namespace std;
int main()
{
bool repeater = true;
do
{
string palindroneCheck;
bool palindronity = true;
cout << "Please enter a line to test for palindromity.\n";
getline(cin, palindroneCheck);
int stringSize = palindroneCheck.size();
int cutOff = stringSize/2;
for (int palindroneLength = 0; palindroneLength < cutOff; palindroneLength++)
{
if (palindroneCheck[palindroneLength] != palindroneCheck[stringSize - palindroneLength -1])
{palindronity = false;
break;}
}
if(palindronity == true)
cout << "Congratulations! This line is a palindrone!\n\n";
else
cout << "Sorry, but this is not a palindrone.\n\n";
palindroneCheck.clear();
char repeat;
cout << "Would you like to try another line? Y/N\n";
cin >> repeat;
if (repeat == "n" || repeat == "N")
repeater = false;
} while (repeater == true);
}
OK, you are right about the spaces. Your code will demand that spaces are in the same location like every other character.
The other bug seems more subtle: it's where you ask to repeat or not.
Why? Because it asks, you enter 'n' and then 'enter'
The cin >> repeat only reads the 'n', but not the 'enter'
so the next time you do `readline(cin,PalindromCheck)' it will read an empty string.
Try to write palindromCheck just after reading it. You'll see.
The reading issue of getline is solved by comments. For the whitespaces, you can tackle it by removing all the spaces inside string palindroneCheck,
std::string::iterator new_end = std::remove(palindroneCheck.begin(), palindroneCheck.end(), ' ');
std::string palindroneCheckWithoutSpaces(palindroneCheck.begin(), new_end);
Then you use palindroneCheckWithoutSpaces to do the Palindrone test.
int stringSize = palindroneCheckWithoutSpaces.size();
int cutOff = stringSize/2;
for (int palindroneLength = 0; palindroneLength < cutOff; palindroneLength++)
{
if (palindroneCheckWithoutSpaces[palindroneLength] != palindroneCheck[stringSize - palindroneLength -1])
{palindronity = false;
break;}
}
if(palindronity == true)
cout << "Congratulations! This line is a palindrone!\n\n";
else
cout << "Sorry, but this is not a palindrone.\n\n";
(you need header algorithm to use remove)
Update:
std::remove remove an element from the input range (this is defined by begin and end here) based on the value you passed in , here is the whitespace ' '. Then it return the new end of the changed range (since you delete something, the range becomes smaller). The new range starts with begin and ends with the returned value.
So the second line you create a new string based on the new range.