2010-11-19 6 views
2

Je suis en train d'écrire un système de test et tout ce que je veux faire est de compter combien de secondes l'utilisateur a passé sur cette question. c'est-à-dire que j'imprime la question (standard System.out.println), puis attendez 5 secondes et si dans ces 5 secondes l'utilisateur a répondu (par l'entrée standard), je veux garder cette valeur. Si l'utilisateur n'a pas répondu dans les 5 secondes, il doit ignorer cette question et continuer. Le problème est - im lecture des réponses des utilisateurs via l'objet Scanner, et quelque chose comme in.nextInt() est incontrôlable, je suppose.Recevoir une entrée à un moment précis

Comment puis-je résoudre ce problème? Voici un fragment de mon code sans cette fonctionnalité, pouvez-vous me donner quelques astuces pour l'ajouter?

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."); 
} 

Répondre

1

J'utiliserais deux threads dans ce cas. Le fil principal écrit des questions, attend des réponses et garde des points. Un thread enfant lit l'entrée standard et envoie les réponses au thread principal, peut-être via un BlockingQueue.

Le fil conducteur peut attendre cinq secondes pour une réponse en utilisant la méthode poll() sur la file d'attente de blocage:

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

Si cet appel retourne null, le thread principal sait que le fil de l'enfant n'a pas reçu toute entrée pendant ce temps, et peut mettre à jour le score de manière appropriée et imprimer la question suivante.

Le ReaderThread ressemblerait à quelque chose comme ceci:

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

} 

Utilisé sur System.in, le Scanner va bloquer jusqu'à ce que l'utilisateur appuie sur Enter, il peut arriver que l'utilisateur a entré un texte mais pas encore pressé Enter quand le thread principal expire et passe à la question suivante. L'utilisateur devra supprimer son entrée en attente et entrer une nouvelle réponse pour la nouvelle question. Je ne connais pas un moyen propre de contourner cette maladresse, car il n'y a pas de moyen fiable d'interrompre l'appel nextInt().

+0

Il peut être boiteux, mais si je vais commencer un nouveau fil après avoir posé une question, appelez wait (timeout) et dans le nouveau thread j'attendrai la réponse et après l'avoir reçu, j'appellerai notify() sur l'objet dans thread parent. Est-ce que ça marchera? – Anton

+0

Je viens de vérifier - cela ne fonctionne pas :) – Anton

+0

Vous pouvez rouler votre propre solution en utilisant 'wait' et' notify', mais comme vous l'avez vu, il est difficile de faire les choses correctement. L'utilisation d'un 'BlockingQueue' est à peu près équivalente, mais elle est incluse dans un paquet propre et fiable. – erickson

Questions connexes