-1

I've been practicing with threads, so I wrote up this timed game where the user needs to guess the correct number (ranges from 1-10). If the user guesses the correct answer in the time limit, the thread stops and the program terminates. It fails to work when the user fails to guess within the time limit. Even though it enters the if-statement after the time limit, it still fails to interrupt the thread completely unless I guess the correct number. I have read other threads but they seem to use ask about the "traditional" guessing game or utilizing Timer. Explanation and/or tips for a suggested solution is also appreciated.

    import java.util.*;
    import static java.lang.System.out;
    import java.io.*;

    public class Threading implements Runnable {
        private static int num;
        private static int k;

    public void run() {
        try {
            Scanner line = new Scanner(System.in);
            k = -1;
            out.println("Guess!");
            while (k != num) {
                k = line.nextInt();
                if (k != num) {
                    out.println("Nope");
                }
            }

        } 
        catch (Exception e) {
            out.println("I'm not done!");
        }
    }

    public static void main(String args[]) throws InterruptedException {

        num = (int) (Math.random() * 9 + 1);
        out.println(num);
        Thread t = new Thread(new Threading());
        t.start();

        long patience = 1000 * 5;
        long startTime = System.currentTimeMillis();
        while (t.isAlive()) {
            t.join(1000);
            if (((System.currentTimeMillis() - startTime) > patience) && t.isAlive()) {
                out.println("I'm in here!");
                t.interrupt();
                t.join();
                out.println("Times up!");
            }
        }
    }
}
Thientvse
  • 1,621
  • 12
  • 21
  • 1
    Possible duplicate of [How to interrupt java.util.Scanner nextLine call](https://stackoverflow.com/questions/4983065/how-to-interrupt-java-util-scanner-nextline-call) – Mark Mucha Nov 18 '17 at 04:45
  • @MarkMucha Is it necessary to use Streams/Buffers for the code to function? Wouldn't there be a way to end the "block" of `nextInt()`? – TypeHereToSearch Nov 18 '17 at 04:49

1 Answers1

0

Since one of the comments already points out that the call to nextInt will block I don't think there is a need to go into the details of that.

So for now I'm going to assume you're fine with allowing the user 1 final guess after the timer expires.

The following is the modified code including my comments. I refer to the thread you named t as the "guessing thread".

private static int num;
private static int k;
//Changed variable "line" to "scanner" and made it static so that the
//  main method can close it once everything is done.
private static Scanner scanner = new Scanner(System.in);

public void run() {
    try {
        k = -1;
        System.out.println("Guess!");
        while (k!=num) {
            //Added a check for interrupt, otherwise this thread will never 
            // end unless the user enters the correct answer.
            if(Thread.currentThread().isInterrupted())
                return;
            k = scanner.nextInt();
            if(k != num){
                System.out.println("Nope");
            }
        }
        System.out.println("Correct!");

    } catch (Exception e) {
        System.out.println("I'm not done!");
    }
}

public static void main(String args[]) throws InterruptedException {

    num = (int) (Math.random() * 9 + 1);
    System.out.println(num);
    //Declared the guessing thread as final so it can be used inside of
    // the TimerTask that is created later.
    final Thread t = new Thread(new GuessUntilTimeLimit());
    t.start();

    long patience = 1000 * 5;

    //Use a Timer to enforce your time limit, the TimerTask will execute
    // an interrupt of your guessing thread if the thread is still alive
    // (it may have died already if user got right answer)
    Timer timer = new Timer();
    TimerTask task = new TimerTask(){

        @Override
        public void run() {
            if(t.isAlive()){
                t.interrupt();
                System.out.println("Times up! Enter your final guess now.");
            }               
        }
    };
    timer.schedule(task, patience);
    //Wait for the guessing thread to finish before canceling the timer
    t.join();
    //By now either the user got the answer or time has run out. Either way
    //  we need to clean up by canceling the timer.
    timer.cancel();
    //Added a call to close the scanner, it's always important to release
    // resources
    scanner.close();
}

Now your main thread schedules a task to execute after patience milliseconds. This task is then responsible for interrupting the "guessing thread". The "guessing thread" will check for interrupt and stop itself when appropriate.

Again, depending on your requirements, you may need to alter the way you accept user input since nextInt will block the thread. For completeness I'm including a link to the question regarding interrupting Scanner.nextLine mentioned in the comments.

D.B.
  • 4,016
  • 2
  • 15
  • 35