Data from table into C++ quiz application

415 views Asked by At

I wrote a code which shows a question and 4 answers, ask to choose the correct one, and checks the choice. Now I would build a table which would contain 6 columns: question/a/b/c/d/correct_answer, and about hundred of lines with my questions. Now I would like my program to randomly choose 5 of a question from table and show it to user.

First question is, can I do my table in Excel and use it than in Visual Studio? If not, what software should I use to do table like this as simply as possible, and how to implement it into my Visual studio project? If yes, how to implement Excel table to my Visual studio project?

Second question is, what simplest code should I write to randomly choose 5 of 100 question from my table?

A code of a question is:

int main()
{

    string ans; //Users input
    string cans; //Correct answer, comes from table
    string quest; //Question, comes from table
    string a; // Answers, come from table
    string b;
    string c;
    string d;
    int points; //Amount of points

    points = 0;

    cout << "\n" << quest << "\n" << a << "\n" << b << "\n" << c << "\n" << d << "\n";
    cout << "Your answer is: ";
    cin >> ans;
    if (ans == cans)
    {
        points = points + 1;
        cout << "Yes, it is correct\n";
    }
    else
    {
        cout << "No, correct answer is " << cans << "\n";
    }


    return 0;
}
2

There are 2 answers

7
Apara On

First Part

You can definitely use Excel to edit your questions and save them. But when you save it, pay attention to the file format.

You want to save your Excel file as a .csv file instead of .xls or .xlsx file. Just go to File -> Save File As -> and change type to .csv.

This is because, reading .csv files is a lot easier. .csv files have each cell in row separated by a comma (,) and each row by a newline ('\n') character.

So, here is a sample Excel file:

Sample Data in Excel format

After I save it as a .csv file and open it using a text editor (Atom, here), it looks like this:

Sample Data in .csv format

After, that you only need to write some code to read the file.

This is the code I used (I've added excessive comments to make the code more explicit for beginners):

#include <iostream>
#include <fstream>
#include <vector>
#include <sstream>

using namespace std;
const int MAX_QUESTIONS = 3;
const int COLUMNS = 6; //Question, Options A, B, C, D, Correct Answer

int main() {

    ifstream fp;
    fp.open("test.csv");

    //If file could not be opened
    if (fp.fail()) {
        std::cout << "failed to open file" << std::endl;
        return 1;
    }

    //Create a 2D vector of strings to store the values in the file
    vector< vector<string> > table;

    string line;

    //Loop through the entire file (fp)
    //Store all values found until I hit a newline character ('\n') in the string line
    //This loop automatically exits when the end-of-file is encountered
    while (getline(fp, line, '\n')) {

        //Create an temporary vector of strings to simulate a row in the excel file
        vector<string> row;

        //Now I am passing in this string into a string stream to further parse it
        stringstream ss;
        ss << line;

        string part;

        //Similar to the outer loop, I am storing each value until I hit a comma into the string part
        while (getline(ss, part, ',')) {

            //Add this to the row
            row.push_back(part);
        }

        //Add this row to the table
        table.push_back(row);
    }

    //Print out the entire table to make sure your values are right
    for (int i = 0; i <= MAX_QUESTIONS; ++i) {
        for (int j = 0; j < COLUMNS; ++j) {
            cout << table[i][j] << " ";
        }
        cout << endl;
    }

    return 0;
}

Second Part

To choose a random number, you can use this code (I borrowed it from another answer)

#include <random>

std::random_device rd;     // only used once to initialise (seed) engine
std::mt19937 rng(rd());    // random-number engine used (Mersenne-Twister in this case)
std::uniform_int_distribution<int> uni(min,max); // guaranteed unbiased

auto random_integer = uni(rng);

Unlike the old method, this doesn't create bias towards the lower end. However, the new engine is available only in C++11 compilers. So keep that in mind. If you need to use the old method, you can correct the bias by following this answer.

To choose 5 different numbers, each time you generate a random number store it in an array and check whether this number has already been used. This can prevent repetition of questions.

1
Tanner Winkelman On

To answer question 1: In Excel, click File>Save As. Choose UTF-16 Unicode Text (.txt), name your file, and save it where your program can access it. In your C++ program, use the fstream library for text files:

#include <fstream>

With the text file in the same directory, use

ifstream fin;
fin.open("FILENAME.txt");
.
.
.
fin >> variable;
.
.
.
fin.close();

To answer question 2: There is a rand() function that returns an integer between zero and RAND_MAX. Then you can use modulus(%) to get a random number in the desired range.

#include <cstdlib> // for srand() and rand()
#include <ctime> // for time()
.
.
.
srand(time(NULL)); // seed the RNG on seconds
.
.
.
var = rand() % ONE_MORE_THAN_MAX;

Here's a quizzer I made to help myself study:

#include <iostream>
#include <fstream>
#include <cstdlib>
#include <cstring>
#include <ctime>
using namespace std;

const char QUESTIONS_FILE_NAME[] = "questions.dat";
const char QUESTION_ANSWER_SEPARATOR = ',';
const char QUESTION_SEPARATOR = '\n';

const short MAX_QUESTION_LENGTH = 300;
const short MAX_ANSWER_LENGTH = 300;
const short MAX_NUM_QUESTIONS = 300;


int main()
{
  char questions[MAX_NUM_QUESTIONS][MAX_QUESTION_LENGTH];
  char answers[MAX_NUM_QUESTIONS][MAX_ANSWER_LENGTH];
  short counter = 0;

  short question_choice;

  char user_answer[MAX_ANSWER_LENGTH];

  ifstream fin;
  fin.open( QUESTIONS_FILE_NAME );


  srand(time(NULL));


  while(fin.getline( questions[counter], MAX_QUESTION_LENGTH-1, 
    QUESTION_ANSWER_SEPARATOR ))
  {
    fin.getline( answers[counter], MAX_ANSWER_LENGTH-1,
      QUESTION_SEPARATOR );
    counter++;
  }

  fin.close();

  cout << endl << "Press CTRL+C to quit at any time" << endl << endl;

  while ( counter > 0 )
  {
    question_choice = rand() % counter;

    cout << endl << questions[question_choice] << " ";
    cin >> user_answer;

    if ( strcmp( user_answer, answers[question_choice] ) )
    {
      cout << endl << "Incorrect" << endl 
        << "It was " << answers[question_choice] << endl;
      strcpy( questions[counter], questions[question_choice] );
      strcpy( answers[counter], answers[question_choice] );
      counter++;
    }
    else
    {
      cout << endl << "Correct" << endl;
      counter--;
      strcpy( questions[question_choice], questions[counter] );
      strcpy( answers[question_choice], answers[counter] );
    }  
  }


  cout << endl << "You Win!!!!" << endl;

  return 0;
}

questions.dat would have data like this

In what year was the Pendleton Civil Service Reform Act enacted?
a.1873
b.1883
c.1893
d.1903,b
In what year did Hurricane Katrina occur?
a.2001
b.2003
c.2005
d.2007,c