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 range-based for 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

687 comments to 5.x — Chapter 5 comprehensive quiz

  • Homero

    I made a really different code for question one and wanted to know what could be improved.

    main.cpp

    • nascardriver

      Hi!

      - Use double literals for doubles (eg. 0.0 instead of 0)
      - Initialize variables instead of assigning to them.
      - `sqrt` should be `std::sqrt`. `sqrt` is the C version of the same function.

      The rest looks good ::)

  • Fabio Henrique

    I tried to fix every issue that you pointed
    constants.hpp:

    main.cpp

    Just some questions:
    -Is it good or bad to have a const function like my clearInput() ? it seems to work pretty fine as a const.
    -And I was trying to remember why did I disallowed 0 and allowed it again after, and it is because of the cin.ignore(), every time it runs on a bad input it transforms the value of guess back to 0 AFAICS, like when a char is input in the guesses... my question is, if we wanted to allow 0 in our gueses, how could we do that and still be able to ignore extraneous input with cin.ignore() ?
    -I just declared maxstreamsize as a long because clangd told me that it would evaluate for a long, it can evaluate for something different in some case ?

    Thanks

    PS: and I knew you probably would react like that, but this formatting is not disgusting for me XD

    • nascardriver

      You still have magic numbers/strings (Line 10, 11, 15, 19, 84, 104, 105).
      Line 107-111: `while (playAgain());`

      > Is it good or bad to have a const function like my clearInput() ?
      That function returns `void`, you can't assign to a `void` anyway, so the `const` doesn't do anything. For other types, it can catch very rare mistakes, but it prevents an important optimization which you'll learn about later (Move sematics). `const` return values do more bad than good (Unless you're returning a reference/pointer (Covered later)).

      > [std::cin] transforms the value of guess back to 0 AFAICS
      That's correct. You should use `std::cin.fail()` to check if extraction failed, not the value.

      > clangd told me that it would evaluate for a long
      Your editor/ide/tool tells you what the type is AFTER preprocessing files. Take this simple example

      If you have a big powerful pc, `streamsize` will be `long long`, and clangd will tell you that it is `long long`. But if someone uses your code on another machine, `streamsize` is a `char`. If you have a look at a reference (A lesson about cppreference is in the making), you'll see that `std::streamsize` is "a signed integral type", but not one type in particular. That's all you can rely on. If your implementation uses a `long`, that doesn't mean every implementation uses a `long`.

      • Fabio Henrique

        I think I understand everything now, I'm sorry if sometimes I take some time to understand but it's because English is not my main language so I have to strive to understand sometimes.

        Now, in constants.hpp:

        In main.cpp:

        Now just a last question, I understand when you say "use consts when working with magick numbers", but what you mean when you say "use consts when working with strings" ?! Is that something like 'magick numbers can be strings too' ?! or I'm misunderstanding ?!
        And I have to start searching more on the references before making these types of questions, thank you for this !

        • nascardriver

          Your `inline`s don't do anything, because the variables are `static` (`inline`: Can be used in multiple files. `static`: Only visible in this file).

          Code looks good now :)

          We say "magic number", but it can be anything. If two things have the same meaning, they should be the same named thing.

          • Fabio Henrique

            oh okay, I got that..
            Magic Numbers can be anything actually, is just a way of naming. Got it!
            and I didn't knew that the compiler would let me define inline and static to the same variable if they are opposites without even issuing a warning or something like that... I'm gonna change just to static then !

            • giang

              Waoh!! I think your code is really good. But there's just 1 thing: I think the "return guess;" in line 45 statement isn't necessary cause you've had one in line 41

  • Fabio Henrique

    to the first question of the quiz, I came out with this solution, and actually I was pretty surprised that it is pretty different than the one you presented here:

    in constants.h:

    untouched

    in main.cpp:

    I saw just now that was said here to another person on the comments section that he modified calculateHeight() and because of that it became not reusable, in mine I tried not to touch any function but the calculateAndPrintHeight() one, since it doesn't have a return that can modify the behavior of the program or of the other functions on it, everything seems to still be reusable AFAICS. Let me know if this solution is good or bad please.
    Thank you!

    • nascardriver

      The reason the code became non-reusable was because the calculation was performed inside of `calculateAndPrintHeight`. In your code, that's not the case. You have a separate `calculateHeight` and `printHeight` function. The height can be calculated or printed without doing the other, good job!
      Your formatting is inconsistent, consider using your editor's auto-formatter.

      • Fabio Henrique

        thank you ! is very nice to know that I'm going the right way :D
        and I don't format my code to post here because it does things that was said here before that were not the style you guys would use in these tutorial series, I'm using NeoVim with Clangd and the formatting defaults to LLVM style, and this does some things like the opening curly brace should always be on the same line that the last statement not on a new line, and the closing curly brace of an if should always be on the same line that the else if it exists, not on a new line, and etc. I prefer this style but in favor of the style you guys prefer I don't format my code to post here. If you think it's ok if I do let me know please

        • nascardriver

          It doesn't matter how you format your code as long as it's consistent, which yours isn't. clang-format can be configured to place braces wherever you like. Even if you can't get it to put the braces where you want, consistency is more important than following some suggestion.

          • Fabio Henrique

            yes, I know it's configurable, actually I already have it configured but it's pretty different than the style that you guys use here, that's what I was trying to say, I was posting the code here trying to follow the code style that you guys like before formatting, actually I always format my code, I already tried other styles but I really like my code compact. And yes, consistence is more important, I'm going to always format my code to post here then.. beginning with my guessing game:
            in constants.hpp

            in main.cpp

            This is the final version of it.
            It looks good or bad in your opinion ?!
            And I did a version using the mersenne twister to practice already, this one with the effolkronium header is just easier and more good looking IMO. And I learned a little bit more after taking a look inside the header code too so I decided to use it.
            Let me know if I'm missing something or if I can improve something please. Thank you !!

            • nascardriver

              > It looks good or bad in your opinion ?!
              Oh that formatting is absolutely disgusting, but if you like it, keep it. Some people like smarts, some people like jeeps, you do you.

              To the code,
              - `std::numeric_limits::max()` returns a `std::streamsize`, not a `long` (It may be a `long`, but it doesn't have to). The type is already in the call, you can use `auto`.
              - Magic numbers/strings, use constants.
              - Line 36: You're disallowing 0 (`!guess` is the same as `guess == 0`), but you're allowing 0 in line 15.
              - Good separation into many functions.
              - Line 72: Use the conditional operator only if you use its result. Don't mix types. `playagain` is a `char`, not a `bool`. `return (playagain == 'y')`;
              - Line 88: The first time this is encountered, it's `true`. Use a do-while-loop instead (That also gets rid of `playing`).
              - You're using a for-loop as if it were a while-loop. Use a while-loop or move `++count` into the loop's header.

  • Eric

    In your answer key to question 2 (your code lines 26 - 37 shown below listed as 1-12),
    why does the line
    36 return (ch == 'y');
    not always cause the function to return ch = 'y'.
    I tested and see that your program works correctly, but to my understanding, since it is after the do loop, it should always happen.  
    What am I misunderstanding?
    P.S. Thank you for undergoing this site.  I have been enjoying learning cpp.

Leave a Comment

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