Guidance on Tutor Program For Myself

Hello,

For a while now, I have wanted to build a tutor program to tutor myself. I have a class right now, for each section we cover we are given definitions with their corresponding keywords and such. Its a lot to memorize at times and flashcards are getting old.

I was hoping I could get some direction on how I should tackle such a thing. The way I envision this working is:


At school, say chemistry class -

we begin a chapter 1 and in it involves atoms: we discover electrons, neutrons, protons.
Electron is Negative charge.
Neutron is Neutral charge.
Proton is Positive charge.

We then start on chapter 2 and in this one we have: Avogadro's Number, Moles
Avogadro's Number is equal to 6.022 x 10^23
Mole is a unit of measure used to convert from elementary entities to grams of that substance.


Mind these definitions are simply examples, however they get the point across hah!

I now have 3 definitions from chapter 1 and 2 from chapter 2. With a fictional exam on these definitions approaching, I would like to study them in a randomized fashion! Firstly by chapter, then ultimately an accumulation of both chapters to prep for a final!

I would like to create predetermined questions along with their answers and spit them out to the user based on a certain 'subject' selection from a main menu. These questions would have a "right or wrong" checker, where entering the wrong answer would flag a "Incorrect! the correct answer is: " or if entered correctly a simple "Goodjob!" would suffice and continue on until exit is initiated.



The program I would like to design would go something like this:

1
2
3
4
5
6
7
8
9
10

Welcome to Chemtutor! Please select an option from the list or enter '4' to exit:

======
1. Chapter 1 (Atoms)
2. Chapter 2 (Conversion Factors)
3. Accumulation
4. Exit
======



Say 1 is selected:

1
2
3
4
5
6
7
8

__Chapter 1 (Atoms)___
An electron's charge is:
a. positive
b. negative
c. does not matter
d. neutral
 


if b is entered a "goodjob!" output is displayed followed by the same chart from before


1
2
3
4
5
6
7
8
9
10

Welcome to Chemtutor! Please select an option from the list or enter '4' to exit:

======
1. Chapter 1 (Atoms)
2. Chapter 2 (Conversion Factors)
3. Accumulation
4. Exit
======


so on and so fourth. However each section would give out a randomized question in its category, and the accumulation would be a combination of both chapters and random as well. I could do boolean and multiple choice questions. However I am not sure the best way to do this. Perhaps arrays of type string? Pointers?

I have made a program similar to this for a c++ class involving math for an elementary student, but not as sophisticated. Also it was with simple numerical inputs and outputs, not strings and such. Here are 2 sections of it for an idea of what I am working towards:

1
2
3
4
5
6
7
8
9
10
11

//output of menu to user
cout <<"Menu\n";
cout <<"1. Addition problem\n";
cout <<"2. Subtraction problem\n";
cout <<"3. Mulitiplication problem\n";
cout <<"4. Division problem\n";
cout <<"5. Exit\n";
cout <<"-----------------------------------\n";
cin >> count;


Output of Addition problem to user:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

//if statement for addition problem
if(count == 1)
			{
//variables declared and assigned
num1 = 1 + rand() % MAX_INT;
num2 = 1 + rand() % MAX_INT;
calculation = num1 + num2;
				
//output of addition problem and input from user
cout << ADD_TEXT << endl;
cout <<" " << num1 << endl;
cout <<"+" << num2 << endl;
cout <<"------\n";
cin >> answer;
				
//if statement used to determine if answer from user input is correct or incorrect
if(answer == calculation)
					{
cout << CORRECT << endl;
cout <<"-----------------------------------\n";
}
else
{
cout << INPUT << answer << endl;
cout << INCORRECT << calculation << endl;
cout <<"-----------------------------------\n";
}
					
}


the random number generator worked but with numbers from 0-10, also the output was numerical and not string. I tried searching online for something similar but to no avail. Any tips on whether arrays of type string might be a solution or if theres something better suited for this? Maybe this is beyond my level of coding but felt the need to ask. Thanks guys.

-Louie
You will find lots of examples of this kind of program in this forum if you search.

You can of course hard code each of the questions and answers, but that gets tedious.

A better approach is to make your program data driven. By that I mean read your questions and answers from a file. Let's assume that you decide on a multi-choice format which always has 4 possible answers. That lets us create a file format something like the following:
1
2
3
4
5
6
7
question
answer a
answer b
answer c
answer d
C   // correct answer
...  Repeat group of 6 lines for every question


Your program would read and display the question and the 4 possible answers, prompt the user for his answer, then compare the users response to the correct answer. Once the user has answered the question, then move on to the next set of six lines in the file for the next question. Continue reading groups of 6 lines until you reach eof on the file.
+1 for data driven, it should be read from a file once the logic is sound

With subtraction, multiplication, and division, you can follow the pattern of your Addition example.
But with the multiple-choice questions and answers, it's a bit more complicated, but not too bad.

So, the problem is that you need a list of strings to keep track of each question, and then you also need 4x {answer letter, answer text} pairs to go with each question.
One solution to this is to internally know that (a.) will be the first index of the answer, (b.) will be the second index, (c.) the third, and (d.) the last index. This way, you only need to have an array of 4 strings associated with 1 question. The best way to enforce this assocation, is (imo) with a struct. You could also use an std::map, but you'd probably want to use a struct either way.

I am using std::vectors instead of raw arrays because they are MUCH easier to manage and pass as arguments.
http://en.cppreference.com/w/cpp/container/vector


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
// Example program
#include <iostream>
#include <string>
#include <vector>

#include <cstdlib>
#include <ctime>


/**
 * Converts 0 -> 'a'
 *          1 -> 'b'
 *          2 -> 'c'
 *          3 -> 'd'
 */
char int_to_char(int choice)
{
    // note: You'll want to do bounds checking before this, to prevent overflow
    return static_cast<char>(choice + 'a');
}

struct Problem {
    
    std::string question;
    std::vector<std::string> answers;
    char correct_answer;
    
    Problem() {} // Default, uninitialized
    
    // constructor that takes in the question and answers
    Problem(const std::string& question_text, const std::vector<std::string>& answer_texts, char correct_answer_letter)
    : question(question_text),
      answers(answer_texts), // copies the vector
      correct_answer(correct_answer_letter)
    {}
     
};

int main()
{
    srand(time(nullptr));
    
    // Create problems:
    Problem chapter1_problems[10];
    chapter1_problems[0] = Problem("An electron's charge is", {"positive", "negative", "does not matter", "neutral"}, 'b');
    // ... fill in the other problems the same way
    
    // Select problem:
    int problem_index = 0; // in reality you'll want: rand() % 10;
    
    // Display problem:
    std::cout << chapter1_problems[problem_index].question << ":" << std::endl;
    for (size_t i = 0; i < chapter1_problems[problem_index].answers.size(); i++)
        std::cout << "  " << int_to_char(i) << ". " << chapter1_problems[problem_index].answers[i] << std::endl;
        
    // Get input
    char answer_letter;
    std::cout << "Enter best choice: ";
    std::cin >> answer_letter;
    
    // Validate:
    if (answer_letter == chapter1_problems[problem_index].correct_answer)
    {
        std::cout << "Correct!" << std::endl;    
    }
    else
    {
        std::cout << "Incorrect." << std::endl;    
    }        
}
Last edited on
Hello louiesluck,

As AbstractionAnon said there are several examples here of people who have done the same type of program.

One of the recent ones I have worked on used a file to load the program with the questions and answers. At the moment I do not remember if a class or struct was used to hold the data for each question, I think it was a class, but a struct would work fine.

The input file had the format of:

type M or F (multiple choice or Fill in the blank) (M) here
chapter number
question
answer
number (number of possible answers)
a. 
b. 
c. 
d.
             // blank line not needed.
type (F)
chapter number
question
answer
             // blank line not needed.

type

and a struct might look like this:

1
2
3
4
5
6
7
struct Question
{
    char s_type;
    std::string s_question;
    std::string s_answer;
    std::vector s_possibilities;
};


Ganado has a good example of how to initialize the struct when it is first created, but I am thinking you would need a function to zero everything out at some point before yo store new info into the struct.

In a function to read the file first read the type letter and based on that use one of two sections to properly read the rest of the information.

Just had a thought that in the data file following type you could put a chapter number and use this when reading the file to put each question into a different vector for each chapter.

Later in the program, using a random number, to choose which vector to use to acquire a question from a different chapter vector. And then a different random number to choose a question from the vector.

Just some thoughts to get you started.

Hope that helps,

Andy
Last edited on
This is what I had in mind:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <vector>
#include <iostream>
#include <fstream>
#include <string>
using namespace std; 

class Question
{   string  m_question;
    string  m_answers[4];
    string  m_correct;
public:
    bool Read (istream & is);
    bool Ask () const;
};

bool Question::Read (istream & is)
{   if (! getline (is, m_question))
        return false;
    for (int i=0; i<4; i++)
      getline (is, m_answers[i]);                
    getline (is, m_correct);
    return true;
}

bool Question::Ask () const
{   string      answer;

    cout << m_question << endl;
    for (int i=0; i<4; i++)
        cout << i+'A' << ". " << m_answers[i] << endl;
    cout << "What is your answer? ";
    cin >> answer;
    return (answer == m_correct);    
}
                    
int main ()
{   ifstream    quiz ("quiz.txt");
    vector<Question>    questions;
    Question            question;
    size_t              asked = 0;
    int                 correct = 0;
            
    while (question.Read (quiz))
        questions.push_back (question);
    while (asked < questions.size())
    {   question = questions[asked];
        if (question.Ask ())
            correct++;
        asked++;
    }
    cout << "You got " << correct << " out of " << asked << " correct." << endl;
    return 0;
} 


Now, all you have to do is write the quiz.txt file.
AbstractionAnon, Ganado, and Handy Andy,

Thank you guys very much for your inputs, I truly do appreciate it! I did not think I would have got this many replies! I apologize for not checking this earlier, was caught up with work and school.

I will give each consideration a try! This was more than enough for me to get started, I will give it a go and report back. Thanks!

Cheers,
Louiesluck
Topic archived. No new replies allowed.