1

I'm relatively new to C++ (and programming in general for the most part) and I'm taking an online course which follows along by teaching with the aim of building a game. In one of the console application projects we have to write code which asks the user if the user wants play the game again.The goal for that part of the program is to ask the user to reply by typing "y" or "n" only and re-ask the question if the user responds by doing something else.

I have attempted to write code which does this and as far as I can see the code works fine. My question is, is the code I wrote valid in the following sense:

  1. Will the code successfully accomplish the outlined task?
  2. Is code like this prone to more errors if it grows later?

The code I have follows. In the main function:

.
.
.
do
{
    PlayGame();
}
while (AskToPlayAgain());

And the function definition for AskToPlayAgain along with an apt description:

bool AskToPlayAgain()
{
 bool Play = true;
 string response = "";
 cout << "Would you like to play again? y/n... ";
 getline(cin, response);

 if (response == "y") { }

 else if (response != "n")
 {
     cout << "Please enter a valid response." << endl;
     // We want AskToPlayAgain called again to ask for a proper response again; however,
     // just calling it outside a conditional will cause the current "Play" value to be returned.
     // This value is true by default and this function will return it even if "n" is entered after
     // an invalid response. As such, in this case, we want this function to be called in the event
     // of an invalid response which will always happen and we don't want the return value of the nested
     // AskToPlayAgain function to be returned, which is true by default unless the program has successfully exited.
     // Furthermore, once the nested AskToPlayAgain returns false, we want the program to exit and not return the "Play"
     // (which is set to true) by the higher level AskToPlayAgain.

     if (AskToPlayAgain()) { }
     else { return false; }
 }

 else
 {
     Play = false;
     cout << "Thank you for playing! :D" << endl;
 }

 return Play;
}

Is the reasoning I presented in the code comments valid? Is there a test case where this would fail? I've tried a few test cases, but all of them worked.

Many thanks for any help on this!

5
  • I've provided some brief pointers in comment. But in general your question is too broad, so I've voted to close. Commented Jan 18, 2018 at 2:43
  • 1. You don't need recursion. Simply use a loop. 2. Because you perform a recursive call every time you get invalid input, if there are enough invalid inputs, you can run out of stack space. 3. Any time you add code you increase risk of error. However, 4. this is not a direct relationship, but a side effect of increased complexity. 5. Your code is unnecessarily complex already: e.g. a) Use of recursion, b) You compare == y but != n, so inconsistent, therefore trickier. (Replaced original comment due to 5 min limit to fix typos) Commented Jan 18, 2018 at 2:45
  • @CraigYoung Why is it too broad? Also, your comment would make a great answer. Commented Jan 18, 2018 at 23:47
  • Recursion by itself is a large topic. Robert C. Martin has written 2 whole books on clean code. There are many ways your code can be prone to errors. Apart from that, while some aspects of code quality can be objectively measured, the question of "good code" is usually subjective. On the whole, while I like your question and the fact you're trying to learn; in its current form your question is not a good fit for this site. Since your code works (albeit with the unnecessary risk I mentioned), your question is much better suited to the sister site: codereview.stackexchange.com Commented Jan 18, 2018 at 23:56
  • @CraigYoung That is an excellent point. I had never even thought of going to code review. Thanks for the reference! Commented Jan 20, 2018 at 3:54

2 Answers 2

3

There is nothing wrong with your recursive method but you can simplify this with a loop, and avoid the potential problems associated with recursion. Loops and recursion are closely related. if (response == "y") { } is not wrong but it's an odd programming practice. If you are not going to do anything upon reaching this condition then don't bother testing for it.

Another method with while loop:

bool AskToPlayAgain()
{
    while(true)
    {
        string response;
        cout << "Would you like to play again? y/n... ";
        getline(cin, response);

        if(response == "y")
        {
            return true;
        }
        else if(response == "n")
        {
            cout << "Thank you for playing! :D" << endl;
            return false;
        }

        cout << "Please enter a valid response." << endl;
    }
}


Edit

Another example with recursive function:

This time we add a counter value for demonstration.

If you run this program and keep giving invalid input, then counter will go up. It shows how the recursive function needs to wait for all other recursive functions to finish.

I added char buf[1000] which is not used. Its purpose is to cause problems!

Potential problem: each function needs to allocate 1000 bytes stack memory (plus memory for other stack variables in the function, and heap memory for std::string). This memory is not freed until the function exists, so it builds up. Stack limit in your program is a few mega bytes, so now there is a potential stack-overflow error.

bool AskToPlayAgain(int counter)
{
    char buf[1000]; //<-- allocate lots of stack memory to cause problems!
    cout << "counter start: " << counter << " - memory allocated\n";

    cout << "play again? y/n... ";
    string response;
    getline(cin, response);

    if(response == "y")
    {
        return true;
    }
    else if(response == "n")
    {
        cout << "Thank you for playing! :D\n";
        return false;
    }

    cout << "invalid response\n";
    bool result = AskToPlayAgain(counter + 1);

    cout << "counter: " << counter << " - memory cleanup\n";
    return result;
}

int main()
{
    do
    {
        printf("play...\n");
    } while(AskToPlayAgain(1));
    return 0;
}

For this reason its better to use loops in favor of recursive functions. But then again, recursive functions are sometimes useful, and if memory allocation is under control (like in your example) and there is clear path to break the recursion, then go ahead and use it.

Sign up to request clarification or add additional context in comments.

3 Comments

I think doing it this way makes a lot more sense. I was just curious about the subtler implications of the code I wrote. I imagine a beginner programmer such as myself would easily set themselves up for "unnoticeable" mistakes like the one in the code I wrote just by writing code which works but isn't recommended. I daresay experience is the teacher one would not prefer in this situation. At any rate, this is a great answer. Thank you!
I see what you mean. I edited the question to show the potential problems with recursive function.
Thank you for adding the extra example! :D
2

i would suggest that in your AskToPlayAgain() function, you do the checking of response == "y" and response == "n" and then do your else section. Although this won't affect your code much, it is certainly easier to read and understand, and if an issue does come up later on , you will not have to spend much time having to go through your code again.

i.e.

if (response == "y") { }

else if (response == "n"){
    // your code
}
else {
    // your code to handle the invalid response
}



Plus, as suggested in the comments and in the answer by @Barmak Shemirani, It would be better to just use a loop to accomplish this task of repeated asking until a valid response. It's "cheaper" than having multiple function calls.

1 Comment

Yes, I've had to rethink my approach entirely on this. The answer here came close to what I wanted to accomplish, but I really need to call that function (or its equivalent) again somehow. But still, it's a good answer. Thank you!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.