1

How to make a program that will ask 5 questions(multiple choice a to d)?
And each question have 30 seconds coundown using thread sleep(return countdown) and when the countdown goes to 0 it will proceed to the next question
and how to add a score using a formula?

import java.util.Scanner;
import java.io.IOException;

class timer{
    public static void main(String[]args) throws IOException{
         Scanner scan = new Scanner(System.in);
         Thread thread1 = Thread.currentThread();
         Thread thread2 = new Thread(() -> {
              try{
                   for(int seconds = 30; seconds >= 0; seconds--){
                        System.out.println("\rYou have "+seconds+"second's left!");
                        Thread.sleep(1000);
                   }
              }catch(InterruptedException e){}
          });
          System.out.println("What is 1+1? ");
          System.out.println("a. 1\t b.2\t c.3\t d.4");
          thread2.start();
          String answer = scan.next();
          thread2.stop();
    }
}
Wen Cy
  • 43
  • 5
  • Is this console application or can you use some GUI elements like dialog windows? – Pshemo Oct 31 '16 at 02:57
  • What's the question? Your example code runs just well as it is, safe using the deprecated `Thread.stop()`. – Janez Kuhar Oct 31 '16 at 03:01
  • 1
    Because how scan.next(); works, it will always stop the thread and wait for the user input. also check this http://stackoverflow.com/questions/5853989/time-limit-for-an-input – Manuel Mejias Oct 31 '16 at 03:09
  • @ManuelMejias `Scanner.next()`, in this example, stops the main thread - `thread1`. `thread2`, however is not affected by it and so the program runs correctly. – Janez Kuhar Oct 31 '16 at 03:19
  • 1
    Wow, only **3** seconds to read a question, read the 4 choices, decide on a choice, then select the choice. You must be expecting super fast readers! – Andreas Oct 31 '16 at 03:28
  • @Andreas Just an example bro. xD – Wen Cy Oct 31 '16 at 06:35

2 Answers2

1

I would personally synchronize my threads using await and signal/signalAll, and rely on the method Condition#await(long time, TimeUnit unit) to know if the answer was given or not while awaiting, so my code would be something like that:

Scanner scan = new Scanner(System.in);
// The lock used to used to synchronize my threads
Lock lock = new ReentrantLock();
// The target condition
Condition answered = lock.newCondition();
Thread thread2 = new Thread(() -> {
    try {
        // Indicates whether the question has been answered
        boolean hasAnswered = false;
        lock.lock();
        try {
            // Loop until the question has been answered or 10 seconds
            for (int seconds = 10; !hasAnswered && seconds >= 0; seconds--){
                System.out.printf("You have %d sec's left!%n", seconds);
                // Wait 1 second and if await returns true it means that
                // I had an answer in time otherwise it means that we
                // reached the timeout without getting answer
                hasAnswered = answered.await(1L, TimeUnit.SECONDS);
            }
        } finally {
            lock.unlock();
        }
        // Print the message indication whether we get the answer in time or not
        if (hasAnswered) {
            System.out.println("Good Job !!");
        } else {
            System.out.println("Too late !!");
        }
    } catch(InterruptedException e){
        Thread.currentThread().interrupt();
    }
});
System.out.println("What is 1+1? ");
System.out.println("a. 1\t b.2\t c.3\t d.4");
thread2.start();
String answer = scan.next();
lock.lock();
try {
    // Notify the other thread that we have an answer
    answered.signalAll(); // could be answered.signal() as we have only 
                          // thread waiting to be notified but it is a 
                          // better practice to use signalAll
} finally {
    lock.unlock();
}

Output in case of a success :

What is 1+1? 
a. 1     b.2     c.3     d.4
You have 10 sec's left!
You have 9 sec's left!
You have 8 sec's left!
You have 7 sec's left!
2
Good Job !!

Output in case it is too late :

What is 1+1? 
a. 1     b.2     c.3     d.4
You have 10 sec's left!
You have 9 sec's left!
You have 8 sec's left!
You have 7 sec's left!
You have 6 sec's left!
You have 5 sec's left!
You have 4 sec's left!
You have 3 sec's left!
You have 2 sec's left!
You have 1 sec's left!
You have 0 sec's left!
Too late !!
Nicolas Filotto
  • 43,537
  • 11
  • 94
  • 122
1

I know this post already has an accepted answer and I really like Nicolas Filotto's answer but I thought I would just share that there is yet another way to accomplish this task (as with anything in Java) and that is by using BufferReader()/InputStreamReader(System.in) which allows you to gather input from the Console without blocking code operation if properly done. Of course an additional thread is used for the question time limit mechanism.

A bit of a twist with this code however, the questions which the User is asked are retrieved from a Text file so that any test can be used with the code. This eliminates the need to hard code the test. Each line within the test text file is a question consisting of three parts (delimited with the Pipe (|) character. The 1st part is the question itself, the 2nd part is the actual answer, and the optional 3rd part is the number of seconds allowed to answer the question. If the 3rd part is not supplied with the question then a default of 10 seconds is used. If 0 is supplied for the 3rd part then the question contains no time limit. The Test file contents should look something like this:

1: What is:  1 + 1 = ?\n   a: 1   b: 2   c: 3   d: 4\n|b|10
2: What is:  5 + 5 = ?\n   a: 1   b: 12  c: 10  d: 15\n|c|20
3: What is:  6 + 4 = ?\n   a: 10  b: 11  c: 12  d: 13\n|a
4: What is:  2 + 3 = ?\n   a: 3  b: 4  c: 5  d: 6\n|c|10
5: What is:  4 + 3 = ?\n   a: 7  b: 6  c: 5  d: 8\n|a|10

As you can see in the file contents question 3 uses the default time limit. The \n and \t tags are permitted within the file text and are handled accordingly within the processing code.

I won't delve into the code operation since I have commented it quite well as to what does what. Here is a full runnable:

package timedquestions;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.LineNumberReader;
import javax.swing.JDialog;
import javax.swing.JOptionPane;

public class TimedQuestions {
    private static String redColor = "\u001B[31m";      // for setting output text color red
    private static String blueColor = "\u001B[34m";     // for setting output text color blue
    private static String purpleColor = "\u001B[35m";   // for setting output text color purple
    private static String resetColor = "\u001B[39;49m"; // for resetting output text color to default
    private static boolean questionAnswered = false;    // Keeps track of whether a question was answered
    private static int questionCount = 0;               // Keeps count of number of questions asked to User
    private static int rightAnswers = 0;                // Keeps count of questions answered Correctly
    private static int wrongAnswers = 0;                // Keeps count of questions answered Incorrectly
    private static int defaultSecondsForTimout = 10;    // The default question time limit
    private static int secondsForTimout = 10;           //Current set time limit for question (can change by question)
    private static boolean timeOut = false;             // Keeps track of whether or not the question has timed out.


    public static void main(String[] args) {
        // Start the test...
        startTest("Test001.txt");  // Your test file path & name goes here.

        // Calculate and display score for test...
        double scr = (double) ((rightAnswers/questionCount)*100);
        int score =  (int) Math.ceil((double)rightAnswers/(double)questionCount*100.0);

        System.out.println("\n======================================================");
        System.out.println("Out of a total of " + questionCount + " questions\n"
                         + "you got " + rightAnswers + " questions Correct and\n"
                         + "you got " + wrongAnswers + " questions Wrong.\n"
                         + "Your score is " + + score + "% "
                         + "which gives you a grade of '" + getLetterGrade(score) + "'.");
        System.out.println("======================================================");

        // Done.
    }

    private static void startTest(String testFilePath) {
        // Get the number of lines (questions) within the supplied Test file...
        int fileLinesCount = 0;
        LineNumberReader  lnr;
        try {
            lnr = new LineNumberReader(new FileReader(new File(testFilePath)));
            lnr.skip(Long.MAX_VALUE);
            fileLinesCount = (lnr.getLineNumber() + 1);
            //System.out.println("Within this Test there are " + fileLinesCount + " questions.");
            lnr.close();
        } 
        catch (FileNotFoundException ex) { System.out.println(ex.getMessage()); return; }
        catch (IOException ex) { System.out.println(ex.getMessage()); return; }

        // Display test information to the User via a Message Box
        // and allow User to start the test.
        String msg = "Within this Test there are " + fileLinesCount + " questions.\n" +
                     "You will have " + secondsForTimout + " seconds to answer each test question.\n" +
                     "If a question runs out of time then you will get that question WRONG.\n\n" +
                     "Press the OK button to start the Test:";
        JDialog dialog = new JDialog();
        dialog.setAlwaysOnTop(true);    
        JOptionPane.showMessageDialog (dialog, msg, "Test Inforamtion...", JOptionPane.PLAIN_MESSAGE);  
        dialog.dispose();

        // Open a Bufferreader to read in questions from the Test file.
        try (BufferedReader fileReader = new BufferedReader(new FileReader(testFilePath))) {
            // Iterate through the Test file and process one question at a time....
            String testFileLine = "";
            while ((testFileLine = fileReader.readLine()) != null) {
                // Split the file line question into specific parts.
                // 1st part will be the question itself, 2nd part will be 
                // the answer and the 3rd part will be the number of seconds
                // allowed to answer question. If the 3rd part is not supplied
                // within the file line question then a default of 10 seconds 
                // is used as set by the defaultSecondsForTimout class global 
                // variable.
                String[] fileQuestionParts = testFileLine.split("\\|");
                String question = fileQuestionParts[0];
                // Allow for newline and tab tags within text string.
                question = "\n" + question.replaceAll("\\\\n", "\n").replaceAll("\\\\t", "\t");
                //Get the question answer from file line
                String questionAnswer = fileQuestionParts[1];
                // If the seconds time out is provided within the question file
                // line then grab it for use. If 0 is supplied then there is no 
                // time limit on that particular question.
                if (fileQuestionParts.length > 2) { secondsForTimout = Integer.parseInt(fileQuestionParts[2]); }
                // otherwise use the default of 10 seconds.
                else { secondsForTimout = defaultSecondsForTimout; }


                String answerResult = "";
                questionCount++;    // Increment the questionCount variable
                questionAnswered = false;   // Set the qustionAnswered variable

                // Ask the retrived question to User....
                answerResult = askTimedQuestion(question, secondsForTimout);
                questionAnswered = true;

                // If the User entered quit then quit the test.
                if (answerResult.equalsIgnoreCase("quit")) { break; }

                // If the User supplied input is the right answer then...
                if (answerResult.equalsIgnoreCase(questionAnswer)) { 
                    System.out.print(blueColor + "  CORRECT\n " + resetColor);
                    rightAnswers++;     // Increment the rightAnswers variable.
                }
                // If the User supplied input is the wrong answer then...        
                else { 
                    wrongAnswers++;     // Increment the wrongAnswers variable.
                    System.out.print(redColor + "  WRONG\n " + resetColor); }
            }
            // Close the file reader.
            fileReader.close();
    }
        catch (IOException e) { 
            // Display file errors
            System.out.println("\nERROR! - " + redColor + e.getMessage() + resetColor); 
        }
    }

    // Method for asking the questions retrieved from the supplied Test file
    private static String askTimedQuestion(String question, int secondsPerQuestion) {
        // The secondsPerQuestion parameter allows you to change
        // the number of seconds for each question if seconds are
        // applied to a particular question within the Test file.
        secondsForTimout = secondsPerQuestion;

        // Establish a new Thread for perform our question timing...
        Thread timerThread = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    // See if this thread has been interrupted. If it has then
                    // we stop our timer While/Loop (a gracefull Thread Stop).
                    while (!Thread.currentThread().isInterrupted()) {
                        for (int seconds = secondsForTimout; seconds >= 1; seconds--){
                            // Break out of this timer FOR loop if the question
                            // was answered by using Thread.interrupt().
                            if (questionAnswered) { Thread.currentThread().interrupt(); break;}
                            // Show that timer is ticking away...
                            System.out.print(purpleColor + "*" + resetColor);

                            // ==========================================================
                            // Or you can use this...
                            //if (seconds < secondsForTimout) { System.out.print("-"); }
                            //System.out.print(seconds);
                            // ==========================================================
                            Thread.sleep(1000);
                        }

                        // If the question wasn't answered and our timer loop has 
                        // expired then inform User that time is up and set the
                        // timeOut variable to true.
                        if (!questionAnswered) { 
                            System.out.print("\b\b\b\u001B[31mYour time is up for this question!\u001B[39;49m");
                            timeOut = true; 
                        } 
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        });

        // Catch Exceptions for BufferReader()/InputStreamReader()...
        try {
            // Declare a BufferReader object so as to get input from User.
            // We use BufferReader along with InputStreamReader(System.in) 
            // for this.
            BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

            // Display the supplied Question from file to User...
            if (questionCount > 1) {
                System.out.println("\n------------------------------------------------------");
            }
            System.out.print(blueColor + "[" + secondsForTimout + " seconds]" + resetColor);
            System.out.println(question);

            // Declare User input variable & initialize to a Null String
            String input = "";      

            // Reset the timeOut variable
            timeOut = false;    

            // Make sure our timer thread is dead before restarting it.
            //while (timerThread.isAlive()){}
            // Start the Timer Thread
            if (secondsPerQuestion > 0) { timerThread.start(); }

            // Loop through input from the User
            do {
                // Wait until we have User input data to complete a readLine()
                // or until our timer thread has set the timeOut variable to
                // true.
                while (!br.ready()) {
                    // If our timer thread has set the timeOut variable to
                    // true then let's get outta this question altogether.
                    // First we get out of our 'wait for input' loop...
                    if (secondsPerQuestion > 0 && timeOut) { break; }
                }
                // Then we get out of our Do/While Loop.
                if (secondsPerQuestion > 0 && timeOut) { break; }

                // No time-out so let's move on...
                // Let's see what the User supplied for an answer.
                // If just ENTER was supplied then input will contain
                // a Null String and the User can still enter an answer
                // until the question is timed out.
                input = br.readLine(); 

                // remove any unwanted text from System.out.print() 
                // that had made its way through the timer thread.
                System.out.print("\b\b\b\b\b");

            } while ("".equals(input));

            // Stop the timer thread.
            timerThread.interrupt();

            return input;
        }
        catch (IOException ex) { return ""; }
    }

    // Determine & return the Letter Grade for the 
    // supplied integer test percentage score. This
    // is a typical North American Standard (I think?).
    private static String getLetterGrade(int score) {
        String grade = "";
        if (score >= 90) { grade = "A"; }
        if (score >= 80 && score <= 89) { grade = "B"; }
        if (score >= 70 && score <= 79) { grade = "C"; }
        if (score >= 60 && score <= 69) { grade = "D"; }
        if (score >= 0 && score <= 59) { grade = "F"; }
        return grade;
    }
}

As I said...just another way.

DevilsHnd - 退職した
  • 8,739
  • 2
  • 19
  • 22