1
\$\begingroup\$

I created a very simple multiple choice math practice game in C for a fun project. Essentially the user first enters how many questions they want, then they enter what operation (+, -, *, /) they want to practice. The game then presents a set of 4 multiple choice answers. The user enters which choice thy think is correct and the program tells them if they were right or wrong. This process continues until the last question, after that the program tells the user the time they took and the percent they got correct.

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <Windows.h>

int TwoDigNum = 0;
int ThreeDigNum = 0;
int Answer = 0;
int NumCorrect = 0;
int TotalProbs = 0;
char StudentAns;
char AnswerLoc;
time_t Start,End;

void AddProbScript(int TwoDigNum, int ThreeDigNum)
{
    printf("Solve the following: %d  +  %d\n", TwoDigNum, ThreeDigNum);
    printf("Here are your choices:\n");

}

void SubProbScript(int TwoDigNum, int ThreeDigNum)
{
    printf("Solve the following: %d  -  %d\n", ThreeDigNum, TwoDigNum);
    printf("Here are your choices:\n");
}

void MultProbScript(int TwoDigNum, int ThreeDigNum)
{
    printf("Solve the following: %d  x  %d\n", TwoDigNum, ThreeDigNum);
    printf("Here are your choices:\n");
}

void DivProbScript(int TwoDigNum, int ThreeDigNum)
{
    printf("Solve the following: %d  /  %d\n", ThreeDigNum, TwoDigNum);
    printf("Here are your choices:\n");
}

int FindAns(char C, int TwoDigNum, int ThreeDigNum)
{
    int Ans = 0;

    switch (C)
    {
    case '+':
        Ans = TwoDigNum + ThreeDigNum;
        break;
    case '-':
        Ans = ThreeDigNum - TwoDigNum;
        break;
    case 'x':
        Ans = TwoDigNum * ThreeDigNum;
        break;
    case '*':
        Ans = TwoDigNum * ThreeDigNum;
        break;
    default:
        Ans = ThreeDigNum/TwoDigNum;
    }

    return Ans;
}

void MakeAnswers(int Ans)
{
    srand(time(NULL));
    int WhereToPut = rand() % 999;
    int Rand1 = rand() % 99;
    int Rand2 = (rand() % 9) * 2;
    int Rand3 = ((rand() % 9) * (rand() % 9))+1;

    if (WhereToPut < 250)
    {
        printf("A.) %d\n", Ans + Rand1);
        printf("B.) %d\n", Ans);
        printf("C.) %d\n", Ans + Rand2);
        printf("D.) %d\n", Ans - Rand3);

        AnswerLoc = 'b';
    }
    if (WhereToPut >= 250 && WhereToPut < 500)
    {
        printf("A.) %d\n", Ans - Rand1);
        printf("B.) %d\n", Ans + Rand2);
        printf("C.) %d\n", Ans + Rand3);
        printf("D.) %d\n", Ans);

        AnswerLoc = 'd';
    }
    if (WhereToPut >= 500 && WhereToPut < 750)
    {
        printf("A.) %d\n", Ans);
        printf("B.) %d\n", Ans - Rand1);
        printf("C.) %d\n", Ans + Rand2);
        printf("D.) %d\n", Ans + Rand3);

        AnswerLoc = 'a';
    }
    if (WhereToPut >= 750)
    {
        printf("A.) %d\n", 2*Rand1);
        printf("B.) %d\n", Ans + Rand2);
        printf("C.) %d\n", Ans);
        printf("D.) %d\n", Ans - Rand3);

        AnswerLoc = 'c';
    }
}

void CheckAnswer(char AnswerLoc)
{
    printf("Enter the choice you think is the answer:");
    StudentAns = getch();
    printf("%c", StudentAns);
    if (StudentAns == AnswerLoc)
    {
        printf("\nGOOD JOB! You got it right!");
        NumCorrect++;
    }
    else
    {
        printf("\nThat's wrong, but keep trying!");
    }

}

int main()
{
    srand(time(NULL));
    printf("How many problems do you want to do?");
    scanf("%d", &TotalProbs);

    Start = clock();

    for (int i = 0; i<TotalProbs ;i++)
    {
        ThreeDigNum = (rand() % 999);
        TwoDigNum = (rand() % 99) + 1;
        printf("\nEnter what operation you want to practice (+,-,x,/):");
        char C = getch();
        printf("%c\n", C);
        switch (C)
        {
        case '+':
            AddProbScript(TwoDigNum, ThreeDigNum);
            Answer = FindAns(C, TwoDigNum, ThreeDigNum);
            MakeAnswers(Answer);
            CheckAnswer(AnswerLoc);
            break;
        case '-':
            SubProbScript(TwoDigNum, ThreeDigNum);
            Answer = FindAns(C, TwoDigNum, ThreeDigNum);
            MakeAnswers(Answer);
            CheckAnswer(AnswerLoc);
            break;
        case 'x':
            MultProbScript(TwoDigNum, ThreeDigNum);
            Answer = FindAns(C, TwoDigNum, ThreeDigNum);
            MakeAnswers(Answer);
            CheckAnswer(AnswerLoc);
            break;
        default:
            DivProbScript(TwoDigNum, ThreeDigNum);
            Answer = FindAns(C, TwoDigNum, ThreeDigNum);
            MakeAnswers(Answer);
            CheckAnswer(AnswerLoc);
        }
    }
    End = clock();
    double PercentCorrect = ((double)(NumCorrect) / TotalProbs)*100;
    double t = (End - Start) / CLOCKS_PER_SEC;
    printf("\nWow you got %d out %d correct! Thats %.2f percent!", NumCorrect, TotalProbs, PercentCorrect);
    printf("Time taken: %.2f seconds\n\n\n", t);
    if (PercentCorrect >= 90.0)
    {
        for (int x = 0; x < 100; x++)
        {
            system("color 0a");
            Sleep(100);
            system("color 0b");
            Sleep(100);
            system("color 0c");
            Sleep(100);
            system("color 0d");
            Sleep(100);
            system("color 0e");
            Sleep(100);
            system("color 0f");
            Sleep(100);
        }
    }
    else
        exit(0);
}
\$\endgroup\$
  • 1
    \$\begingroup\$ "some of the randomly generated answer choices come out to the same number. How can I avoid this?" is off-topic for a review; you're supposed to have the code working as intended before asking for review. \$\endgroup\$ – Toby Speight Apr 2 at 16:00
  • \$\begingroup\$ @TobySpeight The code is working as intended, there is just a slight issue that happens occasionally. I was just seeking some help to see why that is happening. This is not HW or anything I just decided to make this for fun to practice C. \$\endgroup\$ – William H Apr 2 at 22:19
1
\$\begingroup\$

Global Variables

Most of the variables are declared globally, they are not used globally. The general rule to declaring variables is to declare them as you need them and limit the scope of the variable. The reason for this is that it makes the code easier to read and much easier to code and debug. This program is already passing variables as parameters so there really is no need for global variables. The variable NumCorrect should be passed by reference into the function CheckAnswer.

An example, the variables ThreeDigNum and TwoDigNum should be declared in the for loop currently in main:

    for (int i = 0; i<TotalProbs ;i++)
    {
        int ThreeDigNum = (rand() % 999);
        int TwoDigNum = (rand() % 99) + 1;

        ...
    }

This might solve your problem with random numbers.

DRY Code

One software development principle is Don't Repeat Yourself principle.

There is a number of places in the program where code is repeated. In switch statement in the main for loop 3 function calls are repeated 4 times. A variation of the switch statement itself is repeated within one of the function calls. It might be better if the switch statement in the main for loop was removed and have the function FindAns call AddProbScript, SubProbScript, MultProbScript or DivProbScript.

    for (int i = 0; i<TotalProbs ;i++)
    {
        int ThreeDigNum = (rand() % 999);
        int TwoDigNum = (rand() % 99) + 1;
        printf("\nEnter what operation you want to practice (+,-,x,/):");
        char C = getch();
        printf("%c\n", C);

        Answer = FindAns(C, TwoDigNum, ThreeDigNum);
        MakeAnswers(Answer);
        CheckAnswer(AnswerLoc, &NumCorrect);
    }

This would help reduce the complexity of main as well.

Reduce Complexity

The Single Responsibility Principle states that every module, class, or function should have responsibility over a single part of the functionality provided by the software, and that responsibility should be entirely encapsulated by the class (in this case function).

The function main is overly complex. As your C programs get larger the function main should just be a controller that loads the program, calls a function to execute the program and cleans up when the program is complete. The function main currently contains code that should be in at least 2 sub functions. One function might be RunQuiz(int TotalProbs) and the other function might be DoStatistics(time start, time end, int NumCorrect, int TotalProbs).

Use Standard Constants to Make the Code More Readable

The code already includes the stdlib.h header file, rather than using exit(0); it might be better to use exit(EXIT_SUCCESS); or exit(EXIT_FAILURE);. These are more portable.

\$\endgroup\$

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.