Design Pattern in Java for Getting Input and Acting on it - java

I'm trying to make a tic-tac-toe game and I'm encountering a lot of copy-paste work for inputs. I'm trying to figure out what design pattern and implementation works for prompting the user, collecting their input, comparing it and then acting by assigning a value. Right now my code looks like this.
public void promptPlayerCount(BufferedReader in) throws IOException {
String input;
// initial prompt
System.out.println("How many players?");
input = "try again";
while (input.equals("try again")) {
input = in.readLine();
// extract data and check it
switch (Integer.parseInt(input)) {
case 1:
// assignment
playerCount = 1;
break;
case 2:
playerCount = 2;
break;
default:
input = "try again";
// clarified instructions
System.out.println("please enter 1 or 2");
}
}
}
There's a part of me that thinks I could make a function (maybe a factory?) that allows me to generate a function by passing the constructing function the details of the initial prompt, the extraction method, the assignment action and the clarification message.
Would this be best done with lambda functions?

Text input is hard, especially if you can't trust your user (like in a game). Your parseInt will throw a nasty exception right off if your value isn't an integer.
Also standard in is not friendly. I assume this is for an assignment so I won't fault you for using it, but in anything where you don't HAVE to use stdin, don't. The problem is that it's amazingly difficult to get Java to respond to anything less than an entire line with an enter at the end.
When dealing with user input I almost always trim it (Just because they love to insert random white spaces at the beginnings and end) and check to see if it's empty. This could probably be put into a function that also either shows an error or exits the program on "Empty" and otherwise returns a string.
If you often want int values, write a second function that calls the first. Have the second function return an int, but have it catch the exception if the text is invalid and prompt the user again. You could even have this function take a "Range" of integers as a parameter and provide a prompt. So what you have above could look like this:
playerCount = getUserInput("Please enter the number of users", 1, 2);
The rest is wrapped in simple non-redundant functions.
Won't write the code for you because A) it's probably a homework assignment and the fun part is actually coding it and B) someone else probably will provide a full solution with code before I'm done typing this :(
Good luck.

Related

Not sure why my for loop isn't working the way i intended it to

So, before I start I just wanted to say that I'm very new to Java as a language and I've been reading a text book that was recommended to me.
One of the examples provided within the text book on for loops had the following code, which is meant to generate an infinite for loop until the user presses the character 'S' on their keyboard.
Here is the code:
class ForTest {
public static void main(String args[])
throws java.io.IOException {
int i;
System.out.println("Press S to stop.");
for (i = 0; (char) System.in.read() != 'S'; i++)
System.out.println("Pass #" + i);
}
}
I copied the code exactly as it was written within the book but when I run the program, to my surprise, it doesn't start printing out numbers onto the console. Additionally, whenever I press any keys on the keyboard it generates three numbers within the sequence. Example shown below:
I have also included a screenshot of the code from the book below:
I was wondering whether anyone knows why this is the case!
Any help would be greatly appreciated thanks.
The reason it's printing multiple times is because multiple characters are detected.
In your case, it's printing twice because you entered a value (Pass 1) and a new line (Pass 2)
The problem you have is not with System.in.read(), but because the console is usually using a buffered approach. Meaning that data is only transferred to the System.in.read() once you press enter.
So to get the example working, you would have to switch the console to an unbuffered mode, but there is no portable way to do this, because there are so much different types of consoles. Maybe have a look at what editor/console the book is using
This block of code looks like it was written by someone who was deliberately trying to make it obtuse and difficult to comprehend for a beginner.
The middle expression of a for statement is the criterion for taking the next step of the loop. It is evaluated before each step of the loop to determine whether the for loop is complete yet. In this case, it calls in.read() and checks if the input is S before each step of the loop.
in.read() waits for the next line of input it gets. When you enter a value and press Enter, that line gets read, so the loop takes a step. And a new line is also entered, so the loop takes a second step.
It will not print lines to the console unless you enter lines, because in.read() causes the program to block (wait) for the next input.

ArrayList<Integer> is not storing user-inputted integers in Java 8 (1.8)

*EDIT - SOLVED: After instantiating the Scanner Object, I used a delimiter as follows:
scanner.useDelimiter("");
Prior to this, I did try a delimiter that looked something like this (the exact code is available on Stack Overflow):
scanner.useDelimiter("\\p{javaWhitespace}");
...but it didn't work very well.
Thank you, everyone. If you're having this very same issue, try the first delimiter. If it doesn't work, upgrade your JDK to 13 then try it again.
Ok, my goal is to have a user input a credit card number which I would then like to store in an ArrayList of Integers and subsequently pass this list to my functions which will perform the Luhn algorithm in order to validate the provided number. Once the user presses Enter, the processing begins. This is a console application, nothing fancy.
Everything works beautifully...except the user-input part. None of the user-input is being stored into the declared ArrayList. I've inserted a print message to give me the size of the list just after the pertinent while-loop and....yep, 0. I also pass this list into a custom lengthChecker(ArrayList<Integer> list){} function subsequent to the relevant while-loop and it's printing my custom error-message.
I have declared local int variables within the scope of the while-loop and that wasn't helping much. I have tried getting the user's input as Strings and storing them in an ArrayList<String> list; then parsing the input but that didn't work very well (especially as I need the Enter key to behave as a delimiter such that the next steps can take place)
Anyways, here is the code to the function in question. Am I missing something obvious or should I just quit programming?
public void userInput() {
Scanner scanner = new Scanner(System.in);
List<Integer> list = new ArrayList<Integer>();
System.out.println("Please input the card-number to be checked then press Enter: ");
while(scanner.hasNextInt()) {
list.add(scanner.nextInt());
}
System.out.println("Length of list: " + list.size());
listLengthChecker(list);
scanner.close();
}
Thank you in advance.
I don't have the full context on all the code you've written to be able to solve your problem, but I can guess at what's going on. If you want to run any user I/O (such as the scanner), it must occur within the main method. I can only assume that you run your userInput() function within the main method in your class. However, because your userInput() function doesn't have the static keyword in its definition, it can't be accessed without initialising an object of the class - but as far as I can tell from your code, there is no object that the method could refer to. Add the static keyword (i.e. initialise the method as public static void userInput()) to be able to run the function as you intend.
As for the while loop - there's a small chance that this is a difference in Java versions (I use Java 11), but while(scanner.hasNextInt()) won't stop being true at the end of your line or when you press enter - only when you insert something (such as a character) that cannot be interpreted as an integer.
This while loop untill you enter any non integer value.
You finished entering all the integer values and then your program will print your list elements.

Call a Switch with text Strings multiple times using a Scanner

One of the starting assignments in my Java class is to tell a short story using Scanners to get input from the user to choose a part and go Forward/Back.
The start of my code in the main class looks like this:
Scanner sc = new Scanner(System.in);
System.out.println("Which part of my morning would you like to know about? \"Routine\", \"Commute\", or \"At School\"?");
String part = sc.next();
System.out.print(story(part));
I tried building a switch in a separate public static String class and then return it using System.out.print(story(part));. It looks like this:
public static final String story(String part) {
switch (part) {
case "Routine":
System.out.println("I wake up at...");
break;
case "Commute":
System.out.println("I take the bus...");
break;
case "At School":
System.out.println("I hang out with friends");
break;
case "Finish":
System.out.println("Thank you for reading.");
break;
default:
System.out.println("Part title not recognized. Please try again.");
break;
}
return story(part);
While the IDE doesn't show any errors, when I run the code, the output is multiple lines of the selected part and then an error message about the return story(part) line.
I'm just generally confused on how I should approach this task, and how to recall the results of the switch multiple times with the scanner so that I get no Duplicate errors. I don't need a full answer, but some guidance on how to finish this or what I'm doing wrong would be helpful.
Edit: As suggested by #Jb-Nizet, I replaced the System.out.println in the switch with return and removed the return story(part);, which fixed the recursion problem.
Now my remaining question is can I recall the same switch/class in the main class multiple times using Scanners? Or should I create multiple new classes with switches with cases "Next" or "Previous"?
When you get an error then it is a good idea to show it.
I suspect that the error might be a stack overflow error (this site is named after it) because of
return story(part);
That call the function public static final String story(String part) before it was able to finish. The computer needs to remember to finish it so he puts it on "stack" (memory of the computer) and starts to execute the function again and again needs to put it on the stack and eventually it runs out of memory and throws out an error.
Quick fix: Don't call a function inside of that function. Use a cycle outside of the function like:
while(true){
story(part);
}
Fun fact: Calling function inside that function is called recursion and it is a quick inefficient way to program. Next time you use it, make sure it doesn't repeat too many times and always have a way to break the cycle of the function calling itself.

Call a method from a string

I am making a chat. and i have everything working. But i would like to implement commands that the user can run by typing / then the command. I was thinking i would test for the '/' char at index 0. And if thats true i would run that "code". So the user would essentially be calling a method. but i cant figure out how to convert the string into java code. Help would be appreciated. And if anyone has an easier method of how to implement commands feel free to let me know.
Where
String userinput = "/test()";
Thanks
Letting the user actually run code via his input would require 'reflection' (you will find a lot about this by just googling e.g. 'java reflection').
BUT ATTENTION: Letting the user execute Java code this way is a big security problem!
I think the better approach for you would be something like this:
public void executeUserCommand(final String userInput) {
String commandFromUser = // parse fromUserInput
String param = // parse fromUserInput
switch (commandFromUser) {
case "command1":
// call method with 'param'
break;
case "command2":
// call method with 'param'
break;
default:
// tell the user that his command was not found
break;
}
}
You're going to need to look into the Java reflection API to really do anything more than very basic stuff.
At a high level, what I would do is something like this:
/test
or
/msg "John Smith" "XYZ"
You can then parse that into three tokens which gives you msg and two parameters.
What you'll want to do is use reflection to look at the object that handles the chat functions and look up any method named msg that takes two String paramters.
If you decide that allowing numbers and booleans and such is going to be part of it, you're going to get into the weeds pretty fast with the parsing side so be aware of that.
Update: saw this:
"/rep(5,"Hello");
That's going to be a lot harder to parse than /rep 5 "Hello" or /rep 5, "Hello"

How do I use Java's Scanner class to determine the datatype of my input?

[sorry if this is a stupid question, I had a lot of trouble wording it for a google search, and couldn't find any answers to the question, even though it'll probably be like a one-line answer]
I'm just following some tutorials on my Java programming course's website.
Right now I'm coding something that takes will open a prompt screen and be like, "Please enter an integer between 5 and 10: ", and scan the number, and do that for a bunch of different variable types, different boundaries, etc.
Super easy stuff. I just have one small question.
How do I tell my scanning method to check that the variable is of type int? I know it's probably really obvious, but if someone enters "A" or "1.543," I'm supposed to have it display, "That is not an integer!" but I don't know how to actually use the scanner to check variable types
Firstly, because you want to do validation, just read the input in as a String.
String input = scanner.nextLine();
Then you want to check that it's a number. You can use the parse method, wrapped up in a try catch.
try{
int inputDbl = Integer.parseInt(input);
}
catch(NumberFormatException ex)
{
System.out.println("This is not a number");
}
And if you want to do it in a loop, add this try catch to a method that returns a boolean..
public boolean isNumeric(String input)
{
try{
double inputDbl = Integer.parseInt(input);
return true;
}
catch(NumberFormatException ex)
{
return false;
}
}
you can use if(scanner.hasNextInt()){ ... } to see if there is an int next - generally speaking some sequences of characters could be parsed as different types of variables, so you have to use each hasNextDouble(), etc function in the order you desire.
Look here for the complete documentation, which might have many useful functions you are looking for.

Categories