-1

I am writing a multiplication table program to help my niece learn. I want her to be able to have a set amount of time to answer each question (hence the for loop which acts as a delay). The delay works, as after delay seconds the program outputs 'Time's up'! However, the program still waits for me to input a value and press enter before it evaluates answer and checks if it is 'correct' or 'wrong'(this isn't fixed by putting the printf and scanf after the for loop together inside the loop). I know the delay just waits a few seconds and then continues as normal, which is why I need to input a number and press enter. However, I don't know how to get around this.

Basically, I want the program to automatically 'enter' if delay seconds has passed and she hasn't entered a value, resulting in the answer being 'wrong'. But if she enters a value and presses enter before the delay seconds is over, I want to still check if it is either 'correct' or 'wrong'. I have searched for other means of doing this but I simply can't get it right. This is the code so far (again, I know the for loop delay only lets the program wait delay seconds before continuing normally, but I don't know to get around this.

time_t start_time = 0;
int delay = 0;
int answer = 0;
int correct = 0;
int wrong = 0;

printf("How long should the delay be?:\t");
scanf("%d", &delay);

start_time = clock();
printf("\n2 x 4 =\t");

for( ;clock() - start_time <= delay*CLOCKS_PER_SEC; );

printf("\n\nTime's up!\n\n");
scanf("%d", &answer);

if(answer == 8)
{
    printf("\nCorrect!\n");
    ++correct;
}
else if(answer != 8)
{
    printf("\n\aWrong!\n");
    ++wrong;
}

EDIT: I am running Windows and using CodeBlocks with mingw32. I just want the program to be a simple .exe file which will run through CMD. (It does that already though).

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
ThE411
  • 33
  • 8
  • This is heavily dependent on the OS (Windows, Linux, ...). – Jabberwocky Jul 26 '16 at 15:12
  • I asked it, but someone just directed me to a webpage with timers as I asked a question with next to no code with it, I checked on that webpage and this is how far I have come, but I am stumped now. I'll edit the post with my OS and IDE and Compiler. – ThE411 Jul 26 '16 at 15:15
  • Look at [this SO question](http://stackoverflow.com/questions/19955617/win32-read-from-stdin-with-timeout), but it's not straight forward. You probably need to rewrite the input functions to replace scanf (which is a good idea anyway, because scanf if vey bad if the user input cannot be predicted). – Jabberwocky Jul 26 '16 at 15:39
  • The most easy and straightforward way is with *threads*. – n. m. could be an AI Jul 26 '16 at 16:01
  • @n.m.: How is another thread going to help exactly? You still have to cancel the timer in response to the correct input, and cancel input in response to an elapsed timer. Neither one is enabled by throwing a new thread at the problem. You need asynchronous calls. Multithreading is the wrong kind of asynchronous here. – IInspectable Jul 27 '16 at 15:41
  • @IInspectable in the simplest variant just exit the program. This will cancel outstanding actions. If you want to loop, you need to add some synchronization, but there's still no need to cancel anything. You just repurpose the outstanding action for the *next* question. – n. m. could be an AI Jul 27 '16 at 15:56
  • @n.m.: Except, one thread is executing a synchronous `Sleep()` and the other thread is executing a synchronous `ReadFile()`. Who is going to call `exit()`? You completely missed the issue at hand, and the solution is to use asynchronous calls from a single thread, not to use synchronous calls from multiple threads. – IInspectable Jul 27 '16 at 16:04
  • @IInspectable the third (main) one. – n. m. could be an AI Jul 27 '16 at 16:27
  • @n.m.: Right... and when? Anyway, it doesn't look like Windows programming is your strong point. You're probably unaware of the asynchronous I/O API, that makes it possible to implement the requirements on a single thread. And while not trivial, it is loads easier than having to deal with concurrency in a multithreaded application. – IInspectable Jul 27 '16 at 16:38
  • @IInspectable when any of the two other threads finishes. WaitForMultipleObjects, or something. With POSIX threads it's a bit more complicated. I am perfectly aware of asynchronous I/O API. If you want to implement interactive console input with it, good luck. Doable, but totally not newbie-friendly. – n. m. could be an AI Jul 27 '16 at 16:49
  • *"Doable, but totally not newbie-friendly."* - Same goes for multithreading. At any rate, being *"newbie-friendly"* is not the paramount goal of stackoverflow. – IInspectable Jul 27 '16 at 17:11
  • @IInspectable You can show your code and I can show mine, and we will see what is more doable. – n. m. could be an AI Jul 27 '16 at 19:37
  • *"more doable"* is neither measurable, nor (if it were) a communicated goal of answers on stackoverflow. If you need to talk back, have the last word. – IInspectable Jul 27 '16 at 19:39
  • @IInspectable I have posted my answer, you are welcome to critique it. – n. m. could be an AI Jul 27 '16 at 19:49

3 Answers3

2

Your objective cannot be achieved with scanf() as it is a blocking call - Next code line will not be executed until user enters the input. This is not what you want.

You can use another library function kbhit() - It returns > 0 if any key is pressed. But it won't give you which key is pressed. For that you have to call getch().

kbhit is part of conio.h

So your code would be:

bool bAnswered = false;
for( ;clock() - start_time <= delay*CLOCKS_PER_SEC; )
{
     if(kbhit() > 0)  //Some key is pressed
       {
           answer = getch(); //Read that key
           bAnswered = true; // User has answered 
       }
}

// Print message if there wasn't any key press.
if(bAnswered == false)
{
printf("\n\nTime's up!\n\n");
}

if(answer == 8)
{
    printf("\nCorrect!\n");
    ++correct;
}
else if(answer != 8)
{
    printf("\n\aWrong!\n");
    ++wrong;
}

Problem with above code is you can read only 1 character at a time. I leave that to you for implementing. Also, You need to write additional code to convert ASCII to integer as getch() returns ASCII character.

Community
  • 1
  • 1
Swanand
  • 4,027
  • 10
  • 41
  • 69
  • Thank you, I've been struggling for so long. I'm new to C and people keep on downvoting my posts but the fact is just I'm still trying to learn a lot. Thank you again. – ThE411 Jul 27 '16 at 08:20
  • OK now implement line editing on top of that (unless you intend to punish your users for correctable typos). – n. m. could be an AI Jul 27 '16 at 09:33
0

This mostly works. I cannot test the case when the user starts typing and then the timeout expires. I think it should work in Windows but I can only test under Windows emulation which is less than ideal. User may have to press backspace before typing in the next answer.

#include <windows.h>
#include <process.h>
#include <stdio.h>
#include <stdlib.h>

int answer = 0;

DWORD WINAPIinput_thread(void*) 
{
    scanf("%d", &answer);
    return 0;
}

int main()
{
    srand(time(0));

    HANDLE h = (HANDLE)_beginthreadex(0, 5000, input_thread, 0, 0, 0);
    while (1) {
        int u = rand() % 7 + 2;
        int v = rand() % 7 + 2;
        printf ("%d * %d = ?   ", u, v);

        DWORD res = WaitForSingleObject(h, 20000);

        if (res == WAIT_TIMEOUT)
        {
            printf ("\nSorry, timed out!\n");
            FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
        }
        else
        {
            if (answer == u * v)
            {
                printf ("Congrats, you won!\n");
            }
            else
            {
                printf ("Sorry, wrong answer!\n");
            }
            CloseHandle(h);
            h = (HANDLE)_beginthreadex(0, 5000, input_thread, 0, 0, 0);
        }
    }

}
n. m. could be an AI
  • 112,515
  • 14
  • 128
  • 243
-1

Thank you for spending time making sure your niece learns math! A skill we all need more of.

https://gist.github.com/DaemonDave/b2eda8f9fa6b8bbf90a5e1fc1147a461

<script src="https://gist.github.com/DaemonDave/b2eda8f9fa6b8bbf90a5e1fc1147a461.js"></script>

This works as I claimed.

Here is a working math-tester.c file that works on Ubuntu Linux with GCC. You don't need conio, I found a function.

I use 3 things to achieve changes to your requirements. I use kbhit to test for characters to check, I use sleep to wait for second intervals in a while loop, and I use input from command line to ask for the time delay in seconds.

Enjoy!

daemondave
  • 309
  • 2
  • 12