14
\$\begingroup\$

I created a quiz game program with 25 questions, 4 answer choices, correct answer and 4 points awarded per question. I realize this code isn't the best; I am still a beginner and this is my first major project. I am open to criticism and any suggestions on how to shorten this code (especially where the questions are typed with their answers and correct answer).

#include <iostream> 
#include <string>


char guess; //Answer user inputs for question.
int total;  //Total score.


//4 possible answers, correct answer and question score.
class Question{
public:
    void setValues(std::string, std::string, std::string, std::string, std::string, char, int); 
    void askQuestion(); 

private:
    std::string Question_Text;
    std::string answer_1;
    std::string answer_2;
    std::string answer_3;
    std::string answer_4;

    char correct_answer;
    int Question_Score;
};

int main()
{
    //Program Title designed with an ASCII art generator.
    //Link: http://patorjk.com/software/taag/#p=display&f=Graffiti&t=Type%20Something%20
    std::cout << R"(
 _    _      _                            _          _   _            _____              _____       _     
| |  | |    | |                          | |        | | | |          /  __ \ _     _    |  _  |     (_)    
| |  | | ___| | ___ ___  _ __ ___   ___  | |_ ___   | |_| |__   ___  | /  \/| |_ _| |_  | | | |_   _ _ ____
| |/\| |/ _ \ |/ __/ _ \| '_ ` _ \ / _ \ | __/ _ \  | __| '_ \ / _ \ | |  |_   _|_   _| | | | | | | | |_  /
\  /\  /  __/ | (_| (_) | | | | | |  __/ | || (_) | | |_| | | |  __/ | \__/\|_|   |_|   \ \/' / |_| | |/ / 
 \/  \/ \___|_|\___\___/|_| |_| |_|\___|  \__\___/   \__|_| |_|\___|  \____/             \_/\_\\__,_|_/___|

----------------------------------------------By: Joshua Torres---------------------------------------------
    )" << "\n";

    std::cout << "Press enter to start...\n";
    std::cin.get();

    //Get the user's name.
    std::string name;
    std::cout << "What's your name?\n";
    std::cin >> name;
    std::cout << "\n";

    //Ask if user wants to start quiz.
    std::string respond;
    std::cout << "Are you ready to start the quiz, " << name << "? Yes/No.\n";
    std::cin >> respond;

    //If user says yes, the quiz begins.
    if (respond == "Yes" || respond == "yes") {
        std::cout << "\n";
        std::cout << "Good luck!\n";
        std::cout << "\n";
        std::cout << "Press enter to continue.";
        std::cin.get();
        std::cin.ignore();
    }else{
        std::cout << "\n";
        std::cout << "Goodbye!\n";
        std::cin.ignore();
        std::cin.get();
        return 0;
    }//Else, quiz ends.

    //Instances of the questions. 
    //25 questions total generated for this quiz. 
    Question q1;
    Question q2;
    Question q3;
    Question q4;
    Question q5;
    Question q6;
    Question q7;
    Question q8;
    Question q9;
    Question q10;
    Question q11;
    Question q12;
    Question q13;
    Question q14;
    Question q15;
    Question q16;
    Question q17;
    Question q18;
    Question q19;
    Question q20;
    Question q21;
    Question q22;
    Question q23;
    Question q24;
    Question q25;

    //Calling the member function setValues. 
    //Question is set, 4 answer choices, the correct char answer, 4 points per question.
    q1.setValues("1. What command prints something to the screen?",
        "cin",
        "cout",
        "char",
        "print",
        'b',
        4);

    q2.setValues("2. Which of the following categories does C++ belong to?",
        "Operating System",
        "High-level programming language",
        "low-level programming language",
        "Compiler",
        'b',
        4);

    q3.setValues("3. Which command is correctly written?",
        "cout >>",
        "cin <<",
        "cout <>",
        "cin >>",
        'd',
        4);

    q4.setValues("4. What is this called, <iostream>?",
        "directive",
        "pre-processor directive",
        "file",
        "command",
        'b',
        4);

    q5.setValues("5. What punctuation ends most lines of code?",
        " . ",
        " ; ",
        " : ",
        " ' ",
        'b',
        4);

    q6.setValues("6. Which of the following is a correct comment?",
        "*/ Comments */",
        "** Comment **",
        "/* Comment */",
        "{ Comment }",
        'c',
        4);

    q7.setValues("7. Which of the following is the boolean operator for logical-and?",
        "&",
        "|",
        "&&",
        "|&",
        'c',
        4);

    q8.setValues("8. Which of the following shows the correct syntax for an if statement?",
        "if expression",
        "if {expression",
        "if (expression)",
        "expression if",
        'c',
        4);

    q9.setValues("9. How many times is a do while loop guaranteed to loop?",
        "1",
        "0",
        "Infinitely",
        "Variable",
        'a',
        4);

    q10.setValues("10. A subscipt is a(n) __________ .",
        "element in an array",
        "alternate name for an array",
        "number that represents the highest value stored within an array",
        "number that indicates the position of the particular item in an array",
        'd',
        4);

    q11.setValues("11. Which of the following correctly declares an array?",
        "int anarray[10];",
        "int anarray",
        "anarray{10};",
        "array anarray[10];",
        'a',
        4);

    q12.setValues("12. What is the index number of the last element of an array with 29 elements?",
        "29",
        "28",
        "0",
        "Programmer-defined",
        'b',
        4);

    q13.setValues("13. Which is not a loop structure?",
        "for",
        "do while",
        "while",
        "repeat until",
        'd',
        4);

    q14.setValues("14. When does the code block following while(x < 100) execute?",
        "When x is less than one hundred",
        "When x is greater than one hundred",
        "When x is equal to one hundred",
        "While it wishes",
        'a',
        4);

    q15.setValues("15. Most programmers use a for loop __________ .",
        "for every loop they write",
        "when a loop will not repeat",
        "when they do not know the exact number of times a loop will repeat",
        "when they know the exact number of times a loop will repeat",
        'd',
        4);

    q16.setValues("16. Adding 1 to a  variable is also called __________ it.",
        "digesting",
        "incrementing",
        "decrementing",
        "resetting",
        'b',
        4);

    q17.setValues("17. What is required to avoid falling through from one case to the next?",
        "end;",
        "break;",
        "Stop;",
        "A semicolon",
        'b',
        4);

    q18.setValues("18. A __________ is a variable that you set to indicate whether some event has occured.",
        "subscript",
        "banner",
        "counter",
        "flag",
        'd',
        4);

    q19.setValues("19. Identify the C++ compiler of Linux.",
        "cpp",
        "g++",
        "Borland",
        "vc++",
        'b',
        4);

    q20.setValues("20. What is the size of 'int'? ",
        "2",
        "4",
        "8",
        "Compiler dependent",
        'd',
        4);

    q21.setValues("21. Which data type can be used to hold a wide character in C++?",
        "unsigned char;",
        "int",
        "wchar",
        "none of the above.",
        'c',
        4);

    q22.setValues("22. C++ does not support the following",
        "Multilevel inheritance",
        "Hierarchical inheritance",
        "Hybrid inheritance",
        "None of the above.",
        'd',
        4);

    q23.setValues("23. Which is not a protection level provided by classes in C++?",
        "protected",
        "hidden",
        "private",
        "public",
        'b',
        4);

    q24.setValues("24. What purpose do classes serve?",
        "data encapsulation",
        "providing a convenient way of modeling real-world objects",
        "simplifying code reuse",
        "all of the above",
        'd',
        4);

    q25.setValues("25. Who developed the C++ language?",
        "Steve Jobs",
        "Linus Torvalds",
        "Bill Gates",
        "Bjarne Stroustrup",
        'd',
        4);

    //Calling askQuestion member function. 
    q1.askQuestion();
    q2.askQuestion();
    q3.askQuestion();
    q4.askQuestion();
    q5.askQuestion();
    q6.askQuestion();
    q7.askQuestion();
    q8.askQuestion();
    q9.askQuestion();
    q10.askQuestion();
    q11.askQuestion();
    q12.askQuestion();
    q13.askQuestion();
    q14.askQuestion();
    q15.askQuestion();
    q16.askQuestion();
    q17.askQuestion();
    q18.askQuestion();
    q19.askQuestion();
    q20.askQuestion();
    q21.askQuestion();
    q22.askQuestion();
    q23.askQuestion();
    q24.askQuestion();
    q25.askQuestion();

    //Final score displayed when user finishes quiz.
    std::cout << "Your Total Score is " << total << " out of 100!\n";
    std::cout << "\n";

    //User scores above a 69, user passes the quiz.
    //Display message created with ASCII art generator.
    //Link: http://patorjk.com/software/taag/#p=display&f=Graffiti&t=Type%20Something%20
    if (total > 69) {
        std::cout << R"(

__  __               ____                           ____
\ \/ /___  __  __   / __ \____ ______________  ____/ / /
 \  / __ \/ / / /  / /_/ / __ `/ ___/ ___/ _ \/ __  / / 
 / / /_/ / /_/ /  / ____/ /_/ (__  |__  )  __/ /_/ /_/  
/_/\____/\__,_/  /_/    \__,_/____/____/\___/\__,_(_)   

    )" << "\n";
        std::cout << "\n";
        std::cin.get();
        std::cin.ignore();
        return 0;
    }
    else
    {
        std::cout << "You failed... Sorry, better luck next time.\n";
        std::cout << "\n";
    }
    std::cin.get();
    std::cin.ignore();
    return 0;
}

//Function called for question guidelines. 
void Question::setValues(std::string q, std::string a1, std::string a2, std::string a3, std::string a4, char ca, int pa)
{
    Question_Text = q;
    answer_1 = a1;
    answer_2 = a2;
    answer_3 = a3;
    answer_4 = a4;
    correct_answer = ca;
    Question_Score = pa;
}
//Format for possible answers displayed when program executes. 
void Question::askQuestion()
{
    std::cout << "\n";
    std::cout << Question_Text << "\n";
    std::cout << "a. " << answer_1 << "\n";
    std::cout << "b. " << answer_2 << "\n";
    std::cout << "c. " << answer_3 << "\n";
    std::cout << "d. " << answer_4 << "\n";
    std::cout << "\n";

    //User enters their answer.
    std::cout << "What is your answer?" << "\n";
    std::cin >> guess;
    //If their answer is correct, message is displayed and 4 points are added to their score.
    if (guess == correct_answer) {
        std::cout << "\n";
        std::cout << "Correct!" << "\n";
        total = total + Question_Score;
        std::cout << "\n";
        std::cout << "Press enter to continue." << "\n";
        std::cin.get();
        std::cin.ignore();
    }
    else //If their answer is incorrect, message is displayed, no points added. 
         //Correct answer displayed. 
    {
        std::cout << "\n";
        std::cout << "Sorry, you're wrong..." << "\n";
        std::cout << "The correct answer is " << correct_answer << "." << "\n";
        std::cout << "\n";
        std::cout << "Press enter to continue." << "\n";
        std::cin.get();
        std::cin.ignore();
    }
}
\$\endgroup\$
  • 6
    \$\begingroup\$ The more natural way would be to store these questions and answers in a file, and read from that file at runtime. I realise this may become a next stage, but with 25 questions, the majority of your code is (obfuscated with) your questions. \$\endgroup\$ – user86624 Nov 21 '16 at 1:10
  • 2
    \$\begingroup\$ It's a shame I can only +1 once. That ASCII art deserves its own +1. \$\endgroup\$ – phyrfox Nov 21 '16 at 3:30
  • 2
    \$\begingroup\$ Be aware that some of the quiz questions are either incorrect or misleading. For example, questions 1 and 4 are malformed and provide no correct answers. \$\endgroup\$ – Edward May 22 '17 at 0:29
7
\$\begingroup\$

Wow, your code is really nice for a beginner!

First of all, some minor things:

  • If you want to output a single character, don't make it a string, as it will contain 2 characters, instead of one. In your case, '\n' instead of "\n".
  • The yes/no condition will fail if the user accidently had caps lock on. The only is case sensitive, and so your should convert the answer to lower case and compare that:

    // convert string to lower case
    for (auto& c : respond)
        std::tolower(c);
    
    if (respond == "yes") /*...*/
    
  • Using comments is the right way to go, but just like salt, never and too much are harmful. Some comments are really unnecessary, //Else, quiz ends. for example.

  • You don't have to use 2 std::cout expressions to output 2 newlines, just append them:

    std::cout << "...\n\n";
    
  • Stay consistent! For example, some variables in Question start with a list case, while some do not. This can be confusing on large code bases and in the future.

  • Don't use global variables! Why is guess a global variable? It is only used in askQuestion as far as I can see.

    score is a bit trickier, but what you could do is make askQuestion return the amount of points that the user got, so that you can add it in the main function.

  • This is subjective but I would say that it is better to name the parameters of a function in its declaration, so that you don't have to go to the definition to see what to pass to those variables.

  • Instead of total = total + Question_Score; use total += Question_Score;. Less repetition and typing :)

Now how can you shorten the code for the questions, as it is repetitive and long.

For one, it is better to use a constructor instead of a setValues call. That is because imagine you forget to call setValues on a question! The Question will be empty!

The 25 question variables are really crying for an array:

std::vector<Question> questions;

You'll see why I'm using std::vector instead of std::array

Now you can access the questions using indices, questions[4] for question 5, which enables you to change those 25 subsequent askQuestion calls with a simple for loop:

for (const auto& question : questions)
    question.askQuestion();

Once advantage of using std::vector is that you can insert (emplace) elements directly using emplace_back, which shortens the code considerably:

questions.emplace_back("How do I do thing?", "Use jQuery", "C++!!", "JavaScript without jQuery", "I don't know", 'a', 100);

This only works if you write a constructor instead of setValues. It might be better to load the questions from a file though, to avoid recompiling when you want to change questions, remove data from your code which makes your code more readable and so on.

\$\endgroup\$
  • \$\begingroup\$ Thanks for the helpful advice and suggestions! I've done some improvements and I have stored the questions and answers into a vector and .txt file. Would you suggest storing the ASCII art into a file or separate function to declutter a little? \$\endgroup\$ – Torrjv Nov 21 '16 at 20:45
  • \$\begingroup\$ @JoshTorres Honestly, I don't know. It clutters the source file a bit, but it's not that bad. However, don't write a function, use a constant string instead, which you could put on another header file is you want to. \$\endgroup\$ – Rakete1111 Nov 21 '16 at 20:48
8
\$\begingroup\$

Hi and welcome to code review. This already looks quite nice for a beginner, here are some initial thoughts.

When creating a nontrivial class always provide a constructor. That way there is no chance that your class can be used improperly. In your case this would amount to:

explicit Question(const std::string& Question, 
                  const std::vector<std::string>& Answers);

Also I would group things together that belong together, e.g. the answers

std::vector<std::string> answers;

But this also applies for the individual questions themselves.


As you already created a class for the questions, also do so for the players. Again with constructor etc.


Put more functionality into separate functions. This helps to structure your code better. In the end, the game itself should be a class with a player, a vector of questions and the score as members and functionality for the input output.


Rather than asking the questions in the same order every time you can mix them up using std::random_shuffle.

\$\endgroup\$
4
\$\begingroup\$

I'm not a c++ guru as my background is from C#. There are few things I would recommend

  • Rather than having multiple variables for question and answer . I would define two arrays for question and answer
  • Having a Question constructor wold be beneficial as all the values can be set and this will get rid of the setvalues function
  • Your askQuestion is doing too much . The function should not be responsible for displaying right and wrong answers. A separate function called displayAnswers() should be created for this purpose
  • To be honest, I always try to limit my console input/output( e.g cin/cout) to the main function . This helps to decouple your program and also promotes reusability

I hope this helps, goodluck on your C++ journey.

\$\endgroup\$
3
\$\begingroup\$

A further thought, a subclass to the Question class called Answer with a string and a boolean to indicate whether it's the correct answer. This way you can store them in a vector and shuffle them and when an answer is chosen all you need to check is the boolean property to see if it's the correct one.

\$\endgroup\$
  • 1
    \$\begingroup\$ I don't really see this working; if you count incorrect answers then a question should have many answers. Composition over inheritance seems like the way to go here. \$\endgroup\$ – Anton Golov Nov 21 '16 at 9:06
  • \$\begingroup\$ @AntonGolov - The main class can have a collection of answers. When an answer is chosen by the user, finding out whether it's a correct answer is already there. No need to look any further for it. \$\endgroup\$ – tinstaafl Nov 22 '16 at 4:39
  • \$\begingroup\$ If you're shuffling the answers, you can require that the first answer (in the constructor) is always the correct one (and have the constructor mark it as correct). That means less data to enter, and a lower risk of error. \$\endgroup\$ – Toby Speight Mar 13 '18 at 11:06

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.