【问题标题】:Java - How to make a simple examination?Java - 如何进行简单的考试?
【发布时间】:2016-10-31 02:48:44
【问题描述】:

如何制作一个会问 5 个问题(从 a 到 d 多选)的程序?
每个问题都有 30 秒倒计时使用线程睡眠(返回倒计时)
时间> 当倒计时到 0 时,它将进入下一个问题
以及如何使用公式添加分数?

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();
    }
}

【问题讨论】:

  • 这是控制台应用程序还是您可以使用一些 GUI 元素,如对话窗口?
  • 有什么问题?您的示例代码运行良好,使用已弃用的Thread.stop() 是安全的。
  • 因为scan.next();有效,它将始终停止线程并等待用户输入。还要检查这个stackoverflow.com/questions/5853989/time-limit-for-an-input
  • @ManuelMejias Scanner.next(),在这个例子中,停止主线程 - thread1thread2,但不受其影响,因此程序运行正常。
  • 哇,阅读一个问题只需 3 秒,阅读 4 个选项,决定一个选项,然后选择选项。您一定期待超级快速的读者!

标签: java multithreading


【解决方案1】:

我会亲自使用awaitsignal/signalAll 同步我的线程,并依靠Condition#await(long time, TimeUnit unit) 方法来知道在等待时是否给出了答案,所以我的代码会是这样的:

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();
}

成功时的输出:

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 !!

输出以防万一:

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 !!

【讨论】:

    【解决方案2】:

    我知道这篇文章已经有一个公认的答案,我真的很喜欢 Nicolas Filotto 的答案,但我想我只想分享一下还有另一种方法可以完成这项任务(就像 Java 中的任何东西一样),那就是使用 BufferReader()/InputStreamReader(System.in),如果操作正确,您可以从控制台收集输入而不会阻塞代码操作。当然,问题时间限制机制使用了一个额外的线程。

    然而,这个代码有点扭曲,用户被问到的问题是从文本文件中检索的,因此任何测试都可以与代码一起使用。这消除了对测试进行硬编码的需要。测试文本文件中的每一行都是一个由三部分组成的问题(用竖线(|)字符分隔。第一部分是问题本身,第二部分是实际答案,可选的第三部分是秒数允许回答问题。如果问题未提供第 3 部分,则使用默认值 10 秒。如果为第 3 部分提供 0,则问题不包含时间限制。测试文件内容应如下所示:

    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
    

    正如您在文件内容中看到的,问题 3 使用默认时间限制。 \n\t 标记在文件文本中是允许的,并在处理代码中进行相应处理。

    我不会深入研究代码操作,因为我已经很好地评论了它做什么。这是一个完整的可运行文件:

    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;
        }
    }
    

    正如我所说...只是另一种方式。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-12-01
      • 2018-12-14
      • 1970-01-01
      • 1970-01-01
      • 2020-02-29
      • 1970-01-01
      • 1970-01-01
      • 2012-09-06
      相关资源
      最近更新 更多