Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Receive input in specific time

Tags:

java

I'm writing a testing system and i all i want to do is to count how many seconds had user spent on this question. i.e. i print question(standard System.out.println), then wait 5 seconds and if within these 5 seconds user answered(through standard input), i want to keep this value.

If user hasn't provided an answer in 5 seconds, it must skip this question and continue.

The problem is I'm reading user answers via Scanner object, and something like in.nextInt() is uncontrollable, I suppose.

How can I solve this problem? Here is fragment of my code without that functionality, can you give me some hints what to add?

    public void start() {
    questions.prepareQuestions(numQuestions);
    Scanner in=new Scanner(System.in);
    boolean playerIsRight=false,botIsRight=false;
    int playerScore=0,botScore=0;
    for (int i = 0; i < numQuestions; i++) {
        questions.askQuestion(i);
        System.out.print("Your answer(number): ");
        playerIsRight=questions.checkAnswer(i,in.nextInt()-1); //in.nextInt() contains the answer
        botIsRight=botAnswersCorrectly(i + 1);
        if(playerIsRight){ playerScore++; System.out.println("Correct!");}
        else System.out.println("Incorrect!");
        if(botIsRight) botScore++;
        System.out.print("\n");
    }
    if(botScore>playerScore) System.out.println("Machine won! Hail to the almighty transistors!");
    else if(playerScore>botScore) System.out.println("Human won! Hail to the power of nature!");
    else System.out.println("Tie. No one ever wins. No one finally loses.");
}
like image 344
Anton Avatar asked Feb 25 '26 00:02

Anton


1 Answers

I would use two threads in this case. The main thread writes questions, waits for answers, and keeps score. A child thread reads standard input and sends the answers to the main thread, perhaps via a BlockingQueue.

The main thread can wait for five seconds for an answer by using the poll() method on the blocking queue:

…
BlockingQueue<Integer> answers = new SynchronousQueue();
Thread t = new ReaderThread(answers);
t.start();
for (int i = 0; i < numQuestions; ++i) {
  questions.askQuestion(i);
  System.out.print("Your answer (number): ");
  Integer answer = answers.poll(5, TimeUnit.SECONDS);
  playerIsRight = (answer != null) && questions.checkAnswer(i, answer - 1); 
  …
}
t.interrupt();

If this call returns null, the main thread knows that the child thread didn't receive any input during that time, and can update the score appropriately and print the next question.

The ReaderThread would look something like this:

class ReaderThread extends Thread {

  private final BlockingQueue<Integer> answers;

  ReaderThread(BlockingQueue<Integer> answers) { 
    this.answers = answers; 
  }

  @Override 
  public void run() {
    Scanner in = new Scanner(System.in);
    while (!Thread.interrupted()) 
      answers.add(in.nextInt());
  }

}

Used on System.in, the Scanner will block until the user presses Enter, so it might happen that the user has entered some text but not yet pressed Enter when the main thread times out and moves on to the next question. The user would have to delete their pending entry and enter a new answer for the new question. I don't know of a clean way around this awkwardness, since there's not a reliable way to interrupt the nextInt() call.

like image 97
erickson Avatar answered Feb 26 '26 12:02

erickson



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!