0

I am wondering the best way to keep a timer going in the background while a game is played.

I am programming a version of the HiLo game (in Java), which gives a user a certain amount of time to determine a number. If a guess is not correct, the game will tell the user whether the name is too high or too low.

I'm keeping track of time using System.currentTimeMillis() and seeing how much time has elapsed. This seems to work well, and so far I have been checking to see how much time has elapsed each time a new number is entered. For example, currently the app output looks like this:

  Welcome to HiLo! 
  You have 10 seconds to guess a number I'm thinking of between 1 and 100.

  > 67 
  Too high.

  > 29
   Too low.

  Half of your time is gone! Only 5 seconds remains!

  > 37
  Too high.

  > 33

  Oops! Time is up - try again.

As you can see, currently, it can only check when I enter a new number how much time is passed.

I have tried creating a thread to start with a timer, however, when I start it, it keeps counting until the time is exhausted, without going on to the thread.run(int guess) which will be run when there is a new guess. I want to be able to still make guesses while the counter runs. Here is my attempt at a new implementation for thread.start():

public void start(int time_sent) throws InterruptedException {
    time = time_sent; 

    startTime = (System.currentTimeMillis() / 1000);

    while (1==1) {
        long elapsed = ((System.currentTimeMillis() / 1000) - (startTime));
        if (elapsed >= (time)) {
            System.out.println("Oops! Time is up - try again.");
            System.exit(0);
        }
        else if (elapsed >= (time/2) && !halfWarning) {
            System.out.println("Half of your time is gone! Only " + (time/2) + " seconds remains!");
            halfWarning = true;
        }
    }

}

How can I continue running this counter in the background?

Fildor
  • 14,510
  • 4
  • 35
  • 67
Jake
  • 3,411
  • 4
  • 21
  • 37
  • A better option would be to use a Timer. Take a look at http://stackoverflow.com/questions/4044726/how-to-set-a-timer-in-java/4044793#4044793 – mkobit Sep 27 '14 at 21:09
  • Why would you want to write a new thread.start? Can you post more code? – Fildor Sep 27 '14 at 21:14
  • Apart from using a Timer: Re-implementing `Thread.start()` isn`t proper thread handling. See its JavaDoc: _"Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread."_. So your thread's logic has to be implemented in `run()`. The thread ends when its `run()` method ends. See examples at the beginning of `Thread`'s JavaDoc. Furthermore, `System.exit()` is a brute way to end a program. I'd rather let all associated methods end until `main()` finally ends. – Gerold Broser Sep 27 '14 at 21:33

4 Answers4

2

This is one more approach:

public void game() {

    Scanner scanner = new Scanner(System.in);

    int time = 10; // sec

    message("You have " + time + " seconds to guess...");
    new Thread(new Background(System.currentTimeMillis() / 1000, time)).start();

    while (true) {
        String s = scanner.next();

        if (s.equals("55")) {
            message("You win");
            System.exit(0);
        } else {
            message("try again...");
        }
    }

}

private void message(String str) {
    System.out.println(str);
    System.out.print("> "); // monit
}

You start 1 thread with behavior implemented in Background class. Next you enter while loop to capture user inputs. The Background thread works in background...

private class Background implements Runnable {

    private long startTime;
    private long time;
    private boolean halfWarning;

    private Background(long startTime, long time) {
        this.startTime = startTime;
        this.time = time;
    }

    @Override
    public void run() {

        while (true) {
            long now = System.currentTimeMillis() / 1000;
            long elapsed = now - startTime;

            if (elapsed >= (time / 2) && !halfWarning) {
                message("\n Half of your time is gone! Only " + (time / 2) + " seconds remains!");
                halfWarning = true;
            }

            if (elapsed >= time) {
                message("\n Oops! Time is up - try again.");
                System.exit(0);
            }

            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                //ignore
            }
        }
    }
}
przemek hertel
  • 3,924
  • 1
  • 19
  • 27
1

Use a ScheduledExecutorService to execute concurrent actions in the future:

ScheduledExecutorService ses = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture<?> half = ses.schedule(new Runnable() {
    @Override
    public void run() {
        System.out.println("Half of your time is gone!");
    }
}, time / 2, TimeUnit.SECONDS);
ScheduledFuture<?> full = ses.schedule(new Runnable() {
    @Override
    public void run() {
        System.out.println("Oops! Time is up - try again.");
        // System.exit(0) ?
    }
}, time, TimeUnit.SECONDS);

// check
if (input == toGuess) {
    half.cancel();
    full.cancel();
}
Jean Logeart
  • 52,687
  • 11
  • 83
  • 118
  • Nice solution, I didn't know about these classes. Though, what I would do in `full` would be positionning a boolean flag to true, meaning the timer has reached the end, so that the main loop can exit. +1 anyway :) – Dici Sep 27 '14 at 21:28
0

You could have a Timer thread that prints out these messages and shuts down the listening program.

fodon
  • 4,565
  • 12
  • 44
  • 58
0

It might inspire you :

public static class Game extends TimerTask {
    private long    start;
    private long    end;

    public Game(long end) {
        super();
        this.start = System.currentTimeMillis();
        this.end = end;
    }

    @Override
    public void run() {
        while (System.currentTimeMillis() - start < end)
            System.out.println(System.currentTimeMillis());
    }
}

public static void main(String[] args) {
    TimerTask task = new Game(10000);
    Timer timer = new Timer();
    timer.schedule(task,0);
}
Dici
  • 25,226
  • 7
  • 41
  • 82