Receive input in specific time
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 开发者_JS百科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.");
}
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.
精彩评论