Search

5.x — Chapter 5 comprehensive quiz

Quick review

If statements allow us to execute a statement based on whether some condition is true. Else statements execute if the associated if statement is false. You can chain together multiple if and else statements.

Switch statements provide a cleaner and faster method for selecting between a number of discrete items. Switch statements pair great with enumerations.

Goto statements allow the program to jump to somewhere else in the code. Don’t use these.

While loops allow the program to loop as long as a given condition is true. The condition is evaluated before the loop executes.

Do while loops are the same as while loops, but the condition is evaluated after the loop execution. They’re great for menus or things that need to execute at least once.

For loops are the most used loop, and are perfect when you need to loop a specific number of times.

Break statements allow us to break out of a switch, while, do while, or for loop. Or a for each loop, which we haven’t covered yet.

Continue statements allow us to move immediately to the next loop iteration. Be careful when using these with while and do while loops, as your loop counter may not get incremented properly.

And finally, random numbers give us a way to make our programs behave different each time they are run. We’ll see an example of this in the quiz below!

Quiz time!

Warning: The quizzes start getting harder from this point forward, but you can do it. Let’s rock these quizzes!

1) In the chapter 2 comprehensive quiz, we wrote a program to simulate a ball falling off of a tower. Because we didn’t have loops yet, the ball could only fall for 5 seconds.

Take the program below and modify it so that the ball falls for as many seconds as needed until it reaches the ground.

In constants.h:

In your main code file:

Show Solution

2a) Implement a game of hi-lo. First, your program should pick a random integer between 1 and 100. The user is given 7 tries to guess the number.

If the user does not guess the correct number, the program should tell them whether they guessed too high or too low. If the user guesses the right number, the program should tell them they won. If they run out of guesses, the program should tell them they lost, and what the correct number is. At the end of the game, the user should be asked if they want to play again. If the user doesn’t enter ‘y’ or ‘n’, ask them again.

Note: You do not need to implement error handling for the user’s guess.

Here’s what your output should look like:

Let's play a game.  I'm thinking of a number.  You have 7 tries to guess what it is.
Guess #1: 64
Your guess is too high.
Guess #2: 32
Your guess is too low.
Guess #3: 54
Your guess is too high.
Guess #4: 51
Correct! You win!
Would you like to play again (y/n)? y
Let's play a game.  I'm thinking of a number.  You have 7 tries to guess what it is.
Guess #1: 64
Your guess is too high.
Guess #2: 32
Your guess is too low.
Guess #3: 54
Your guess is too high.
Guess #4: 51
Your guess is too high.
Guess #5: 36
Your guess is too low.
Guess #6: 45
Your guess is too low.
Guess #7: 48
Your guess is too low.
Sorry, you lose.  The correct number was 49.
Would you like to play again (y/n)? q
Would you like to play again (y/n)? f
Would you like to play again (y/n)? n
Thank you for playing.

Hints:
* If your compiler is C++11 capable, use the Mersenne Twister algorithm from chapter 5.9 -- Random number generation to pick a random number.
* If your compiler is not C++11 capable, you can use rand() (also presented in chapter 5.9 -- Random number generation) to pick a random number
* Write a function that allows the user to play a single game of hi-lo.
* Write a function that asks the user if they want to play again and handles the looping logic for an incorrect input.

Show Solution

2b) Update your previous solution to handle invalid input (e.g. ‘x’) or valid input with extraneous characters (e.g. “43x”) when the user is guessing a number.

Hint: Write a separate function to handle the user inputting their guess (along with the associated error handling).

Show Solution

6.1 -- Arrays (Part I)
Index
5.11 -- Introduction to testing your code

411 comments to 5.x — Chapter 5 comprehensive quiz

  • DAT

    Quiz 2:
    #include"stdafx.h"
    #include<cstdlib>
    #include<iostream>
    #include<ctime>

    void playGame()
    {
        std::srand(static_cast<unsigned int>(std::time(nullptr)));

        int randomNumber = 1 + (std::rand() % 100);

        for (int i = 1; i <= 7; i++)
        {
            std::cout << "Guess #" << i << ": ";
            int number;
            std::cin >> number;
            if(std::cin.fail())
            {
                std::cin.clear();
                std::cin.ignore(32767, '\n');
                 }
            if (number == randomNumber)
            {
                std::cout << "Correct! You win!" << "\n";
                return ;
            }
            else if (number < randomNumber)
                std::cout << "Your guess is too low" << "\n";
            else
                std::cout << "Your guess is too high" << "\n";
        }
        std::cout << "Sorry, you lose. The correct number was " << randomNumber << "\n";
        return ;
    }

    void playAgain()
    {
        playGame();
        while (true)
        {
            std::cout << "Would you like to play again (y/n)? ";
            char play_again;
            std::cin >> play_again;
            std::cin.ignore(32767, '\n');
            if (play_again == 'y')
                playGame();
            else if (play_again == 'n')
                return;
        }
    }

    int main()
    {
        std::cout << "Let's play a game. ";
        std::cout << "I'm thinking of a number. You have 7 tries to guess what it is" << "\n";
        playAgain();
        
        return 0;

    }

  • Kio

    For Quiz 2.

    It's not the best code, but some alternative work to @Alex

    @nascardriver hit me with improvements 🙂 Much appreciated. And thank you for your work and comments 🙂

    • Hi Kio!

      * Initialize your variables with uniform initialization
      * Use @std::numeric_limits<std::streamsize>::max() instead of 32767
      * The random device and mersenne twister should be static
      * @validateInput: Unused parameter
      * Use @std::size_t instead of @size_t. Since you're not using @i for a function that requires an @std::size_t, use an int.
      * Use ++prefix unless you need postfix++
      * Line 76: Use while (true)
      * @main: Use a do-while-loop to prevent the duplicate call to @playGame

      • Kio

        You are the machine 🙂

        Can you provide an example of "do - while" loop for my current example, I'm bit tired so, any boost would help?

  • Kio

    Nice alternative to Quiz 1. I've just pasted code that was modified

  • Terra'Navis

    If anyone could advise I was wondering if someone could tell me if there is anything wrong or poorly made about my version of quiz 2a), also am i committing any bad practices.

    • Hi Terra!

      * Initialize your variables with uniform initialization
      * Avoid abbreviations unless their meaning is obvious
      * Use ++prefix unless you need postfix++
      * @getRandomNumber shouldn't create a new mersenne twister every time it is called.
      * Line 53: Unnecessary. You only need to return from non-void functions.
      * Line 65: Unnecessary
      * Line 75 should be merged with @repeatPlay to avoid to duplicate call in line 75 and 64

      • Terra'Navis

        Hi thank you for your comments they are very useful, just a few questions on some of them if you have the time:
        *am i not using uniform initialisation for every variable except uChoice?, also why is uniform initialisation important?
        *why is it better to use ++prefix over postfix++
        *"line 75 should be merged with @repeatPlay", why is the duplicate call bad? also is this a good solution:

        • > am i not using uniform initialisation for every variable except uChoice?
          Line 19, 20, 21, 23, 61.
          Line 35 and 36 should be one line.

          > why is uniform initialisation important?
          It disallows implicit casts which would go unnoticed with other initializations and could cause undesired behavior. There are more reasons, but this is why I use it.

          > why is it better to use ++prefix over postfix++
          If it wasn't for compiler optimization, ++prefix would be faster, because postfix++ needs to store the unmodified value of the variable

          > why is the duplicate call bad?
          Duplicates are always bad, because they mean extra work when updating something.
          Imagine the call wouldn't be as simple as it is now. If there were a lot of arguments and maybe calculations you'd need to perform before you call @playGame. Those would be needed in both places and they'd always need to be the same. Why do it twice when you can do it once?

          > is this a better solution
          It is. Try using a do-while-loop to avoid the comparison in line 5 on the first run, because it will always be true.

  • Sam

    My solutions, any feedback is welcome:

    Question 1:

    Question 2:

    • Hi Sam!

      General
      * Initialize your variables with uniform initialization

      1
      * Inconsistent variable name style
      * Line 5: Use -= for better readability
      * Use double literals when calculating with doubles (2.0 instead of 2)
      * If @initialHeight is 0.0, no message will be printed

      2
      * @PlayHiLo: Unused return value
      * @main: Missing return-statement
      * Don't use @exit unless there is not way around it. If you have to use it, use @std::exit
      * A do-while-loop is better suited in @main to avoid the duplicate call to @PlayHiLo (Line 54, 63)

  • Dr.Abbas

    Hello
    I honestly don't know if saying thank you is enough but, THANK YOU!. I appreciate what you are doing.

    well i tried to experiment with somethings while working the quiz.
    1) i was wondering if i could print the time?. i tried cout with & without staticcast to int

    2) can i make a function that has >2 parameters but will still function if i pass 1 without saying "not if arguments"

    3) if 2 is possible can i can make the function do different statements according to which arguments i pass

    4) can a function return more than one value at the same time

    5) if 4 is possible can it return different types at the same time, i.e (returning int to an int variable but can also return string to string variable)

    my code works as i intended but i'm sure there is many things wrong with it and my style.
    so please show me whats wrong and how i can make it better or shorter or more functional.
    how can i improve please.

    • Hi Dr. Abbas!

      1. For everything related to time, @std::chrono is your friend
      2,3. Lesson 7.6 and 7.7
      4,5. Lesson 4.7 or 6.10, 6.11, 7.3 and 7.4

      References
      std::chrono::system_clock::now - http://www.cplusplus.com/reference/chrono/system_clock/now/

    • I forgot your code,

      * @std::srand should only be called once.
      * Initialize your variables with uniform initialization. Preferably to a specific value.
      * @compare: Missing return value
      * Line 70: Unnecessary comparison
      * Line 93: Unnecessary
      * A bool is false/true
      * @main: Missing return statement
      * Line 121: Without code, there's nothing I can tell you

  • Leo Prast

    I am sure somebody must have noticed and remarked on it (apologies if so), but technically, should I not check and handle std::cin fail state before I ask for the number as well as after?

    It seems the current standard answer only checks afterwards.

    Sure, it would only result in a double line of input request, and in this program a failure should not be possible at that point, but that may not be guaranteed when reusing the code.

    • Alex

      Yes, if you're writing a reusable module, it would be good practice to ensure all of the streams are in a good state before you try to use them, just in case.

      I don't tend to do that in most of these programs for conciseness reasons.

  • Josh

    When I tried doing the first program in the quiz, it keeps telling me there is no file in directory even though I have the file with the same name as you. Please help. Thank you

  • KitsuekiDC

    Here's what I came up with. It's a little different than the shown solution (and lacks sufficient commenting) but it the first solution I thought of.

    • Hi Kitsueki!

      * Every call to @std::cin.ignore: Use @std::numeric_limits<std::streamsize>::max() instead of 32767.
      * Every variable declaration: Use uniform initialization
      * Magic numbers, 0, 1, 7, 100. Use constants. The description of the game you're printing doesn't correspond to what's actually happening (0-100, 1-100).
      * Line 68: The value of @playAgain is never used before it's overridden in line 96. Either remove this variable or initialize it to 0. Otherwise the reader might think this value is important.
      * You're using the same name style for variables and functions, this can get confusing in bigger projects.

      References
      Lesson 2.1 - Fundamental variable definition, initialization, and assignment
      std::basic_istream::ignore - http://www.cplusplus.com/reference/istream/basic_istream/ignore/#parameters

      • KitsuekiDC

        Thanks for the tips. I might create a function to return the max limit instead of typing that out each time.
        I'm so used to direct initialization I always forget about uniform, I'll have to practice it. I forgot to update that output after I realized we were going for 1-100, thanks for pointing it out!

        For @playAgain, do you mean like 'char playAgain {};'?

        • Use curly brackets when it's a complex type (struct, class, std). A char can easily initialized to a known value

  • Nam Le

    It looped indefinitely and i don't know why? Thanks in advance to Alex and nascardriver!

    • Hi Nam Le!

      The loop in @main will only stop when @x < 0.0, but @x doesn't ever get modified and remains it's initial value.

      • Nam Le

        Thanks for your help! I totally don't remember what was i doing lol ( I need to get better naming scheme ).This is my solution:

        Are there any better solutions to this would you suggest?
        Your input is greatly appreciated!

        • This snipped
          * Line 3, 4, 5, 6: Use uniform initialization
          * Line 12, @groundCommand: Double comparison of @y to 0.0. Also, should be >, not >=

          Previous code
          * Everywhere: Use uniform initialization
          * Move main below other functions to avoid forward declarations
          * Use @std::numeric_limits<std::streamsize>::max() instead of 32767
          * Line 46, 47: Favor initialization over assignment
          * Line 47: Use double numbers when calculating with doubles (2.0 instead of 2)
          * Unused function: @generateSeconds
          * Inconsistent formatting. Use the auto-formatting feature of your editor

          • Nam Le

            Can you show me where and when to use uniform initialization?
            I already read Alex's instructions but i don't understand.Can you elaborate it out for me?
            Also in quiz 2, why shouldn't we use <random> header instead of using the std::rand() ? Didn't Alex say that: "std::rand() is a mediocre PRNG"? Is there a limitation to what we can use in <random>?

            • > Can you show me where and when to use uniform initialization?
              Every initialization should be uniform initialization. Every variable should be initialized.
              @main would look like this

              > why shouldn't we use <random> header
              I don't know what Alex did there, use <random>. Maybe Alex wrote this quiz before he added <random> to lesson 5.9

              • Nam Le

                I appreciate your help, nascardriver! If anyone is planning on developing the quiz 2 program using <random>, i will save you the hassle from searching, go to http://randomlib.sourceforge.net/html/index.html . Good luck!

                • The code required for the number generation is max 5 lines. If that's too much for you to write on your own you might as well learn java or some other language.

                  • Nam Le

                    I'm so sorry :(. I was just trying to provide documentation about the <random> header from the owner since Alex was planning on teaching the <random> in future lessons.

                    Edit : nascardriver is correct, this is an oversight on my part( The link above leads to the header that <random> header succeed). Thanks for the help again @nascardriver!

                    • That's not <random> though, that's some custom library.
                      Have a look at these documentations
                      http://www.cplusplus.com/reference/random/
                      https://en.cppreference.com/w/cpp/header/random

              • Alex

                Yes, the quiz precedes C++11 and the addition of topics around the random header. I'll update the answer.

  • Hi,

    I appear to have an issue:

    although I use the time to seed and call rand() to get a second number (VS bug) it always returns the same number.  Also, my playNext() function always returns true for either y or n and for errornous entry goes into an infinite loop....

    • Sorted the playNext() issue - changed

      to

      now to try and sort out the random number generator.

    • Hi Nigel!

      Your random number generation works for me, check if @std::time is working correctly by comparing the time to what is displayed at https://www.epochconverter.com/

      Other issues you appear to have:
      * A strong issue with using uniform initialization.
      * Use ++prefix unless you need postfix++
      * Use @std::rand, @rand isn't guaranteed to be declared in the global namespace.
      * Line 53, 37: Duplicate constant

      • in debug, it is telling me that both STD::SRAND and STD::RAND could not be evaluated as they are both undefined. I thought they were both defined in the cstdlib header?

        • They are. Sorry, but I have no idea what your debugger's issue is. Try printing the values to the console to check them out instead of debugging your program.

          • changed it to this to try a different random number generator:

            but the answer is still always 7, which is the same as

            .

            • I see the problem. I'll show it to you when you're using uniform initialization. If you don't want to, you can look for it yourself, there's an issue with the parameters/arguments of one of your own functions.

              • ok, uniform initialisation but I still don't see how it helps:

                • Good start,
                  * Line 17-19 are still not using uniform initialization
                  * Line 20 should be merged with 21, use initialization, not assignment
                  * Line 27: Initialize chars to 0, '\0' or '\x00'
                  * Line 41, 62, 66, 72: That's still copy initialization
                  * Line 44: Missing initialization alltogether

                  Next hint: Take a close look at line 38 and 72.
                  Use uniform initialization all the way to unlock the detailed answer.

                  • Woohoo! Got it!

                    Thank you!!!

                    I suppose it's bad habits picked up from coding in C and C#. As they say, it's harder to learn the correct way after picking up bad habits already.

                    • > I still don't see how it helps
                      Forgot that in my last reply. Uniform initialization is easier to differentiate from a function call (cpp syntax can get weird). More importantly (for me at least), uniform initialization doesn't allow implicit casts that could potentially cause data loss.

                      What you're doing

                      is not uniform initialization. The right hand side is an @std::initializer_list, which is then implicitly cast to a bool in a copy initialization, that's even worse than leaving out the curly brackets.
                      Uniform initialization has the brackets right after the identifier, there is no equals sign involved.

                  • Final solution then:

                    • If you still have some motivation left for this quiz, which I understand if you don't, here are my suggestions:

                      * Line 17-19, 43: Uniform initialization
                      * Line 32,33: Double comparison of @choose to 'y'
                      * Inconsistent formatting, use the auto formatting feature of your IDE
                      * Magic numbers: 1, 100. Declare constants
                      * You're using the same name style for variables and functions, this can become confusing in bigger projects.

                      Just look at the suggestions and remember them for the next quiz. Overall you've done a good job.

Leave a Comment

Put all code inside code tags: [code]your code here[/code]