How to stop waiting for user input? - java

I'm building a programm to ask multiplication and I want to set up a timer to force the person to give its answer in a given time :
if the person answers before the end of the timer : go next multiplication
if the timer reach its end, stop waiting user input : go next multiplication
For the moment, case 1 can be done, but 2 not, I was thinking about a way to return; from the method within like a Thread or something, bu I don't know how
So I'm facing a problem, if a Scanner is open, waiting for input, how to stop it ? I've tried putting it in a Thread and interrupt() it or using boolean as flags, but it doesn't stop the Scanner
class Multiplication extends Calcul {
Multiplication() { super((nb1, nb2) -> nb1 * nb2); }
#Override
public String toString() { return getNb1() + "*" + getNb2(); }
}
abstract class Calcul {
private int nb1, nb2;
private boolean valid;
private boolean inTime = true;
private boolean answered = false;
private BiFunction<Integer, Integer, Integer> function;
Calcul(BiFunction<Integer, Integer, Integer> f) {
this.nb1 = new Random().nextInt(11);
this.nb2 = new Random().nextInt(11);
this.function = f;
}
void start() {
Scanner sc = new Scanner(System.in);
System.out.println("What much is " + this + " ?");
Timer timer = new Timer();
timer.schedule(new TimerTask() {
#Override
public void run() {
if (!answered) {
inTime = false;
}
}
}, 5 * 1000);
int answer = Integer.parseInt(sc.nextLine());
if (inTime) {
checkAnswer(answer);
timer.cancel();
}
}
private void checkAnswer(int answer) {
System.out.println("You said " + answer);
valid = (function.apply(nb1, nb2) == answer) && inTime;
answered = true;
}
int getNb1() { return nb1; }
int getNb2() { return nb2; }
boolean isValid() { return valid; }
public static void main(String[] args) {
List<Calcul> l = Arrays.asList(new Multiplication(), new Multiplication(), new Multiplication());
l.forEach(Calcul::start);
}
}

You can check for System.in.available() > 0 to see if there is a line to read. Only if this returns true call the sc.nextLine() to actually receive the input.
An example:
Scanner sc = new Scanner(System.in);
long sTime = System.currentTimeMillis();
while (System.currentTimeMillis() - sTime < 5000)
{
if (System.in.available() > 0)
{
System.out.println(sc.nextLine());
}
}
sc.close();
This reads from the console for 5 seconds if there is something to read and just prints it out again. Note: When actually using this you would probably throw a sleep in the loop to not hug to many system resources.
Please note that this is a can work solution: available() tends to be an unreliable method that does some estimation and can be in the wrong. I would probably not rely on it in a time-critical system, etc.
Also to further expand, this approach relies on the console to work the way most consoles work (in other words: All consoles that I know of): Only when the user enters a newline (by e.g. pressing enter) the line is actually given to System.in to process. Else available() would already return true when only one character gets typed.

have you tried to use close, you can check if the input is "" when the time is up and close it, might help;
if(scanner!=null)
{
scanner.close();
}

Related

When I run my methods it keeps repeating itself and doesn't move on java

Like the caption said the method "scanInput1" runs two times in a row when it should only run once. Then the method "arrayskapare" runs as intended but after that. instead of running the method "medelvarde" is jumps back and runs "scanInput1" again and again and again
import java.util.*;
class Heltalshanterare{
private static String scanInput1(){
System.out.print("Skriv in antal heltal: ");
Scanner scr = new Scanner(System.in);
String antalHeltal = scr.next();
try {
Integer.parseInt(antalHeltal);
}
catch (NumberFormatException e) {
System.out.println("Ogilitigt värde");
scanInput1();
}
return antalHeltal;
}
private static List<Integer> arrayskapare() {
int antalangivnatal = Integer.parseInt(scanInput1());
int noll = 1;
int heltal = 0;
String tal1 = "";
Scanner tal = new Scanner(System.in);
List<Integer> list = new ArrayList<>();
while (noll <= antalangivnatal) {
noll++;
heltal++;
System.out.print("ange heltal " + heltal + ": ");
tal1 = tal.next();
try {
int num = Integer.parseInt(tal1);
list.add(num);
} catch (NumberFormatException e) {
System.out.println("Ogiltigt värde");
noll--;
heltal--;
}
}
return list;
}
public static int medelvarde(){
int antalsiffror = arrayskapare().size();
int sum = 0;
for (int i : arrayskapare()){sum += i;}
int medelvärde = sum / antalsiffror;
System.out.println("medelvärdet av dina tal är " + medelvärde);
return medelvarde();
}
public static void main(String [] args){
scanInput1();
arrayskapare();
medelvarde();
}
}
Im sorry that the code is so long but I have been struggling with this for too long and I really need some help.
Your main method is calling each method just once, which is what you need. But it's not actually holding onto any of the values being returned. So the number of heltal (integers in English) is captured from the user but then never actually stored anywhere. And later an array of numbers is captured but not stored anywhere.
Your second, bigger problem is that your methods are then calling the earlier methods all over again. So instead of asking the user to type in the data just once, you're forcing them to answer the exact same questions multiple times.
A much tidier approach is to alter your methods so that they take the required data as a parameter. Which means your arrayskapare (array producer) method should take the antalHeltal (number of integers) value as a parameter, and then it won't need to call the scanInput1 method again. Same thing can be done for your medelvarde (mean value) method: have it take the array as a method parameter, so that it won't need to call arrayskapare.
With those changes your main method can simply look like this:
public static void main(String [] args){
int antalHeltal = scanInput1();
List<Integer> heltalArray = arrayskapare(antalHeltal);
int medelvardet = medelvarde(heltalArray);
System.out.println("Medelvärdet är " + medelvardet);
}
Now each method just gets called once and the data captured from the user gets stored into variables and passed along the river of methods until the final result is reached.

Elevator: User input

I'm trying to make an application which copy an elevator operation (2 floors). But when I ask the user which floor he want to go, there are 2 differents possibilities. The first one, user enter a floor and the elevator move. The second one, after 10 secondes, still no response from user, at this point, the elevator have to close his door and turn off the light.
So my probleme is with the timeout, because I want my "while" to continue.
My main:
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.Timer;
import java.util.TimerTask;
public class TP5 {
private String floorAsk = "";
TimerTask task = new TimerTask() {
public void run() {
if (floorAsk.equals("")) {
System.out.println("No response ...");
task.cancel();
}
}
};
public boolean getInput() throws Exception {
Timer timer = new Timer();
timer.schedule(task, 10 * 1000);
BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
floorAsk = in.readLine();
timer.cancel();
System.out.println("Floor ask " + floorAsk);
return true;
}
/**
* main.
* #param args ceci est un String[]
*/
public static void main(String[] args) {
Controller c = new Controller();
Door p = new Door();
Light l = new Light();
Engine m = new Engine();
Button b = new CallButton();
while (true) {
Scanner sc = new Scanner(System.in);
System.out.println("What is your floor ?");
String actualFloorString = sc.nextLine();
int actualFloor = Integer.parseInt(actualFloorString);
if (actualFloor == 0 || etageAct == 1) {
System.out.println("You are at floor " + actualFloorString);
if (actualFloor != c.getShaft()) {
if (actualFloor > c.getShaft()) {
m.up();
} else if (actualFloor < c.getShaft()) {
m.down();
}
}
if (!l.isOn()) {
l.on();
}
if (!p.isOpen()) {
p.open();
}
System.out.println("Which floor do you want to go ?");
try {
(new TP5()).getInput();
} catch (Exception e) {
System.out.println(e);
}
System.out.println("test");
} else {
System.out.println("Please enter a valid floor (0 or 1)");
}
}
}
}
I try to use this solution: Time limit for an input
but I want to go back in my "while" and I don't know how to do it or if I'm using the right way to do it.
I also have some other class, Contoleur, Lumiere, Moteur, Porte, Bouton. But I haven't code the functions yet.
Thanks for you answer
EDIT
Ok I maybe find a way, I modify my code and now I have a function which take in parameter the scanner and a String:
public static int ask(Scanner sc, String t) {
System.out.println(t);
return sc.nextInt();
}
And I was wondering that maybe it's possible to put a timeout on a function. Do you know if it's possible ?
I would suggest the use of the Timer class.
https://docs.oracle.com/javase/7/docs/api/java/util/Timer.html
After a 10 second timeout, have the timer call a method that "closes" the elevator door.
The Timer can be canceled if the user inputs a valid integer. A new timer can be created when the door opens.
Edit: I didn't see you were already using the Timer object as I was scrolled down to the main method.

How to keep asking for a console input running even after program execution

I am trying to execute a program after taking user input from the console. [code block below]. However, I do not want to terminate after the program execution finishes. I want the console to always ask me the INITIAL_MESSAGE after the execution finishes. Effectively, after the execution of the program, I want the console to again ask me the INTIAL_MESSAGE so that I can again enter the inputs as I want and execute the program again.
I am actually calling the interactor() in this method, from the main method as the starting point.
Please tell me how do I achieve this
public class ConsoleInteraction {
/**
* #param args
*/
public static int numberOfJavaTrainees ;
public static int numberOfPHPTrainees ;
Barracks trainingBarrack = new Barracks();
public void interactor() throws IOException {
//reading capability from the consolemessages properties file
ResourceBundle bundle = ResourceBundle.getBundle("resources/consolemessages");
// Create a scanner so we can read the command-line input
Scanner scanner = new Scanner(System.in);
// Prompt for training or viewing camp
System.out.print(bundle.getString("INITIAL_MESSAGE"));
//Get the preference as an integer
int preference = scanner.nextInt();
//Show options based on preference
if(preference == 1)
{
//System.out.println("Whom do you want to train?\n 1.Java Guy \n 2.PHP Guy \n 3.Mix \n Enter You preference:");
System.out.print(bundle.getString("WHO_TO_TRAIN"));
int traineepreference = scanner.nextInt();
if (traineepreference == 1)
{
//System.out.println("How many Java guys you want to train ? : ");
System.out.print(bundle.getString("HOW_MANY_JAVA"));
numberOfJavaTrainees = scanner.nextInt();
trainingBarrack.trainTrainees(numberOfJavaTrainees, 0);
}
else if (traineepreference == 2)
{
//System.out.println("How many PHP guys you want to train ? : ");
System.out.print(bundle.getString("HOW_MANY_PHP"));
numberOfPHPTrainees = scanner.nextInt();
trainingBarrack.trainTrainees(0, numberOfPHPTrainees);
}
else if (traineepreference == 3)
{
System.out.print(bundle.getString("HOW_MANY_JAVA"));
numberOfJavaTrainees = scanner.nextInt();
System.out.print(bundle.getString("HOW_MANY_PHP"));
numberOfPHPTrainees = scanner.nextInt();
trainingBarrack.trainTrainees(numberOfJavaTrainees, numberOfPHPTrainees);
}
else
{
System.out.print(bundle.getString("ERROR_MESSAGE1"));
}
}
else if (preference == 2)
{
System.out.println("Showing Camp to You");
System.out.println("Java trained in Trainee Camp : "+ TraineeCamp.trainedJavaGuys);
System.out.println("PHP trained in Trainee Camp : "+ TraineeCamp.trainedPHPGuys);
}
else
{
System.out.print(bundle.getString("ERROR_MESSAGE2"));
}
scanner.close();
}
}
Consider these changes quickly drafted to your class. Might not compile. Might not work as you planned.
Some highlights of what I think you should change:
Use constants for the choice values. Makes your code way more better to read.
Initialize Bundle and Scanner outside of the method. Might be reused.
instead of coding lengthy parts of code inside of the if-else-if cascade, call methods there - angain increasing your readability a long way
public class ConsoleInteraction {
public static int numberOfJavaTrainees ;
public static int numberOfPHPTrainees ;
//Don't read that every time...
ResourceBundle bundle = ResourceBundle.getBundle("resources/consolemessages");
public static void main(String[] args) {
//Moving Scanner out of loop
try {
Scanner scanner = new Scanner(System.in);
ConsoleInteraction ci = new ConsoleInteraction();
//Loop until this returns false
while(ci.interactor(scanner)) {
System.out.println("=== Next iteration ===");
}
} catch (IOException e) {
e.printStackTrace();
}
}
//Constant values to make code readable
public final static int PREF_TRAINING = 1;
public final static int PREF_SHOW_CAMP = 2;
public final static int PREF_QUIT = 99;
public boolean interactor(Scanner scanner) throws IOException {
// Prompt for training or viewing camp
System.out.print(bundle.getString("INITIAL_MESSAGE"));
//Get the preference as an integer
int preference = scanner.nextInt();
//Show options based on preference.
if(preference == PREF_TRAINING) {
//LIKE YOU DID BEFORE OR calling method:
readTraining(scanner);
} else if (preference == PREF_SHOW_CAMP) {
//LIKE YOU DID BEFORE OR calling mathod:
showCamp();
} else if (preference == PREF_QUIT) {
//Last loop
return false;
} else {
System.out.print(bundle.getString("ERROR_MESSAGE2"));
}
//Next loop
return true;
}
}

How would I store the health values and run again until either player health == 0 or enemy health == 0

What would be the best way for me to code the the actual attack / defend between the two characters and how would I store the health value so that re attacks could be stored until either player health or enemy health reached 0, and then declare the victor. This is my first ever attempt at any kind programming after self teaching from various sources, please also give me feed back on any improvement I could make, I'm sure there will be many.
Thank you in advance.
:-)
package test;
public class BattleClass {
public static void main(String[] args) {
PlayerStats ps = new PlayerStats();
EnemyStats es = new EnemyStats();
int eh = es.getEnemyHealth();
int ph = ps.getPlayerHealth();
ps.PlayerAttackDefend();
es.AttackDefend();
System.out.println("You chose to " + ps.getpInput() + " and rolled "
+ ps.getPlayerRoll());
System.out.println("The enemy chose to " + es.getEaod()
+ " and rolled " + es.getEnemyRoll() + ".");
if (ps.getpInput().equals("Attack")) {
if (es.getEaod().equals("Attack")) {
System.out
.println("YOUR SWORDS BOUNCE OFF EACHOUTHERS... TRY AGAIN!");
System.exit(0);
}
if (es.getEaod().equals("Defend")) {
if (ps.getPlayerRoll() > es.getEnemyRoll())
eh -= ps.getPlayerRoll() - es.getEnemyRoll();
System.out.println("Enemy Health is " + eh);
}
}
if (ps.getpInput().equals("Defend")) {
if (es.getEaod().equals("Defend")) {
System.out
.println("YOUR SHIELDS BOUNCE OFF EACHOTHERS... TRY AGAIN!");
System.exit(0);
}
}
if (es.getEaod().equals("Attack")) {
if (es.getEnemyRoll() > ps.getPlayerRoll())
ph -= es.getEnemyRoll() - ps.getPlayerRoll();
System.out.println("Your Health is " + ph);
}
}
}
package test;
import java.util.Random;
import java.util.Scanner;
public class PlayerStats {
static Scanner paod = new Scanner(System.in);
//Players initial health value.
private int playerHealth = 10;
//RNG for attack value / defence value using dice as object.
private int playerRoll = new Random().nextInt(6) + 1;
private String pInput;
//Method for selecting Attack or Defence.
public void PlayerAttackDefend() {
System.out.println("Do you want to Attack or Defend?");
System.out.println("a = Attack / d = Defend");
//Player selects attack or defend.
String userInput = paod.nextLine();
if (userInput.equals("a")) {
pInput = "Attack";
}
if (userInput.equals("d")) {
pInput = "Defend";
}
}
public static Scanner getPaod() {
return paod;
}
public int getPlayerHealth() {
return playerHealth;
}
public int getPlayerRoll() {
return playerRoll;
}
public String getpInput() {
return pInput;
}
public static void setPaod(Scanner paod) {
PlayerStats.paod = paod;
}
public void setPlayerHealth(int playerHealth) {
this.playerHealth = playerHealth;
}
public void setPlayerRoll(int playerRoll) {
this.playerRoll = playerRoll;
}
public void setpInput(String pInput) {
this.pInput = pInput;
}
}
package test;
import java.util.Random;
public class EnemyStats {
//Enemy initial health value.
private int enemyHealth = 10;
//RNG for attack value / defence value using dice as object.
private static int enemyRoll = new Random().nextInt(6) + 1;
//RNG for enemy decision to Attack or Defend.
private static int eAttackDefend = new Random().nextInt(2) + 1;
//Used for returning attack or defend string.
private static String eaod;
//Attack or Defend method.
public void AttackDefend() {
if (eAttackDefend == 1) {
eaod = "Attack";
} else {
eaod = "Defend";
}
}
public int getEnemyHealth() {
return enemyHealth;
}
public int getEnemyRoll() {
return enemyRoll;
}
public int geteAttackDefend() {
return eAttackDefend;
}
public String getEaod() {
return eaod;
}
public void setEnemyHealth(int enemyHealth) {
this.enemyHealth = enemyHealth;
}
public void setEnemyRoll(int enemyRoll) {
EnemyStats.enemyRoll = enemyRoll;
}
public void seteAttackDefend(int eAttackDefend) {
EnemyStats.eAttackDefend = eAttackDefend;
}
public void setEaod(String eaod) {
EnemyStats.eaod = eaod;
}
}
An easy way would to be to set maxHp and actualHp values, if you want to be able to "heal".
If you just decrease until one is dead, you can just decrease the actual health variable you already have.
You might wanna take a look at Inheritance in general, as you have a lot of duplicate code.
In general, just make a loop
while(ps.getHealth() > 0 && es.getHealth() > 0) {
// your battle code
}
you might want to remove the System.exit(0) calls, as they terminate the program.
Add to the player/enemy a dealDamage(int damage) method to actually be able to reduce their health
The health values should be in the objects, and you should not need to store them in your BattleClass.
I could give you the short answer but I guess you get more out of a detailed explanation :-)
You want to run your code "until either player health or enemy health reached 0" so you need a loop.
In java you have 3 kinds of loops:
The for loop
for(int i=1;i<=3;i++) System.out.println("Hello Musketeer Nr. "+i);
The most elaborate loop, the for loop consists of three parts, the initialization, the condition, and the afterthought. While the for loop can be used differently, it is mostly is used in the fashion shown here, that is, you have a counter variable whose value you need somehow.
If you don't need the counter variable value, you can use the short form with collections and arrays:
for(Person p: persons) System.out.println("Hello, "+person.getName()+"!");
The while loop
The second most commonly used (at least by me) loop, it has an initial condition and iterates, as long as it is true.
while(ph>0&&eh>0)
{
...
}
As you see, it fits your problem very well. For completeness, I will however describe the third loop which is the
do-while loop
do
{
...
}
while(ph>0&&eh>0)
You use this loop like the while loop but if you want to have at least one run through.
Other Remarks
Why have two classes PlayerStats and EnemyStats in combat system (they both seem to have the same actions and values) ? You could just have:
Stats playerStats=new Stats();
Stats enemyStats=new Stats();

Java: Using a timer with a quiz

I'm trying to implement a time limit a user has to answer a question in a quiz. Although I have found quite a bit on timmers I don't know how to piece it all together.
I want the user to have 15 seconds to answer the question. If they answer it in time, it checks if answer the answer is correct and then asks them if they want to continue to the next question.
If the user gives no response in the 15 seconds then it should say that the answer is incorrect and gives them the option to move to the next question.
Here is what I have so far.
for(int i=0; i<quiz.getQuizQuestions().size(); i++){
super.getQuestion(i);
//While timer is less than 15 seconds
getResponse(i, questionStart);
//If time has run out output "You have run out of time"
super.nextQuestion();
}
It is probably worth knowing:
super.getQuestion(i) is just printing the question being asked
getResponse() is waiting for keyboard input. if something is entered then it checks to see if the user is correct.
super.nextQuestion() asks the user is they want to move onto the next question
Thanks in advance
EDIT: It would also be amazing if it was easy to implement a counter that counted down from 15 when converting this into a GUI.
uses ExecutorService and Future to make sure we read a line or interrupt it. Code is a little longer than I expected... Let me know if something is unclear:
import java.util.concurrent.*;
import java.io.*;
public class Test {
public static void main(String[] args) throws java.io.IOException {
Question q = new Question();
System.out.println("You have 5 seconds: " + q.toString());
String userAnswer = null;
ExecutorService ex = Executors.newSingleThreadExecutor();
try {
Future<String> result = ex.submit(new GetInputLineCallable());
try {
userAnswer = result.get(5, TimeUnit.SECONDS);
if (Integer.valueOf(userAnswer) == q.getAnswer()){
System.out.println("good!");
}
else{
System.out.println("Incorrect!");
}
} catch (ExecutionException e) {
e.getCause().printStackTrace();
} catch (TimeoutException e){
System.out.println("too late!");
return;
} catch (InterruptedException e){
System.out.println("interrupted?");
e.getCause().printStackTrace();
}
} finally {
ex.shutdownNow();
}
}
}
class GetInputLineCallable implements Callable<String> {
public String call() throws IOException {
BufferedReader inp = new BufferedReader(new InputStreamReader(System.in));
String input = "";
while ("".equals(input)) {
try {
while (!inp.ready()) {
Thread.sleep(100);
}
input = inp.readLine();
} catch (InterruptedException e) {
return null;
}
}
return input;
}
}
class Question{
int p1, p2;
public Question(){
p1 = 2;
p2 = 3;
}
public String toString(){
return String.format("%d + %d = ?", p1, p2);
}
public int getAnswer(){
return p1+p2;
}
}
long startTime = System.currentTimeMillis();
while(System.currentTimeMillis() - startTime < 15000){
if(userAnswered){
break; // if there is an answer we stop waiting
}
Thread.sleep(1000); // otherwise we wait 1 sec before checking again
}
if(userAnswered){
goToNextQuestion();
}
else {
handleTimeOut();
}

Categories

Resources