Using chars, created by a scanner - java

I'm trying to make a basic text game in Java. I decided just to make a game off of the console because that's the only way I know how. I'm trying to use chars to see if what the user typed contains the letter h at position 0, it worked fine when I tried it in the main method, but it's not working when I call it as a separate method.
import java.util.Scanner;
public class testing
{
static Scanner kb = new Scanner(System.in);
public static void main(String[] args)
{
System.out.println("Wanna start the game?");
System.out.println("1. Start");
System.out.println("2. Quit");
int ans = kb.nextInt();
if(ans == 1)
{
levelOne();
}
else
System.out.println("Quitting");
}
public static void levelOne()
{
System.out.println("Type something");
char letter = kb.nextLine().charAt(0);
if(letter == 'h')
{
System.out.println("contains h");
}
else
System.out.println("does not contain h");
}
}

Because nextInt doesnt consume any non-numeric input you need to consume the newline characters passed by the method before nextLine is invoked
kb.nextLine(); // added
char letter = kb.nextLine().charAt(0);

remove spaces first then get the character
char letter = kb.nextLine().trim().charAt(0);
input 1 hello
notice space before hello
Output:
Wanna start the game?
1. Start
2. Quit
1 hello
Type something
hello
does not contain h

Related

How to re-write an input loop to not contain code repetition?

I have the following code, which continues to ask the user to enter a letter as long as the letter is either "a" or "b":
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
String letter;
System.out.print("Enter a letter: ");
letter = scan.nextLine();
while(letter.equals("a") || letter.equals("b"))
{
System.out.println("You entered: " + letter);
System.out.print("Enter a letter: ");
letter = scan.nextLine();
}
}
}
But the following code is repeated twice:
System.out.print("Enter a letter: ");
letter = scan.nextLine();
Is there a way to make the above code only appear one time?
while (true) {
System.out.print("Enter a letter: ");
String letter = scan.nextLine();
if (!letter.equals("a") && !letter.equals("b"))
break;
System.out.println("You entered: " + letter);
}
This is the classic example of a loop that is neither naturally while-do nor do-while — it needs to exit from the middle, if you want the same behavior and also to reduce code duplication.
(Notice also that the variable declaration letter has been moved to an inner scope since it is no longer needed in the outer scope.  This is a small positive indication.)
As an alternative to while (true) some languages allow degenerate for-loop as in for(;;).
The below reverses the logic of the conditional loop exit test, at the expense of more control flow logic.
while (true) {
System.out.print("Enter a letter: ");
String letter = scan.nextLine();
if (letter.equals("a") || letter.equals("b")) {
System.out.println("You entered: " + letter);
continue;
}
break;
}
(There is no difference between these in efficiency terms — these are equivalent at the level of machine code.)
do while loop
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
String letter;
do{
System.out.print("Enter a letter: ");
letter = scan.nextLine();
System.out.println("You entered: " + letter);
}while(letter.equals("a") || letter.equals("b"));
}
}
It will loop once first, and then continue again if the statment is true.
You need to perform three sequential actions in a loop:
read the input entered by the user;
validate the input;
print the input, but only if it is valid.
That means that conditional logic must reside inside the loop before the statement that prints the input. And that makes the condition of the loop redundant. Instead, we can create an infinite loop with a break statement wrapped by a condition, that validates the input.
While loop
That's how it can be done using a while loop:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String letter;
while (true) {
System.out.print("Enter a letter: ");
letter = scan.nextLine();
if (!letter.matches("[ab]")) break;
System.out.println("You entered: " + letter);
}
}
Method matches() that expects a regular expression as argument is used in the code above to simplify the termination condition.
For more information on regular expressions, take a look at this tutorial
For loop
Regarding the advice of utilizing a for loop - that's doable, but by its nature the task of reading the user input fits better in the concept of while loop because we don't know the amount of data in advance, and the iteration can terminate at any point in time.
Also note syntax of the for statement consists of three parts separated with a semicolon:
initialization expression - allow to define and initialize variables that would be used in the loop;
termination expression - condition which terminates the execution of the loop;
increment expression - defines how variables would change at each iteration step.
All these parts are optional, but the two semicolons ; inside the parentheses always have to be present.
Because as I've said earlier, the input needs to be validated inside the loop, we can't take advantage from the termination expression and increment expression.
For the sake of completeness, below I've provided the version of how it can be achieved using a for loop:
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
for (String letter = "a"; ;) {
System.out.print("Enter a letter: ");
letter = scan.nextLine();
if (!letter.matches("[ab]")) break;
System.out.println("You entered: " + letter);
}
}
The only advantage is that the scope of the variable letter was reduced. But approach of utilizing while loop is more readable and expressive.
Alternative approach
Another option is to preserve your initial structure of the code:
initialize the variable letter before the loop, at the same line where it is defined;
enter the loop if letter holds a valid input;
print the input and reassign the variable.
But in order to avoid duplication of the code line responsible for printing the prompt and reading the input will be extracted into a separate method.
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String letter = readInput(scan);
while (letter.matches("[ab]")) {
System.out.println("You entered: " + letter);
letter = readInput(scan);
}
}
public static String readInput(Scanner scan) {
System.out.print("Enter a letter: ");
return scan.nextLine();
}
As Bobulous mentioned, a do-while loop is another simple solution. If duplicating the conditional is still a deal-breaker for you, though, you can also create a function that returns a boolean, and, when true, prints the extra text.
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
String letter;
do
{
System.out.print("Enter a letter: ");
letter = scan.nextLine();
} while(inputIsAOrB(letter));
}
public static boolean inputIsAOrB(String input) {
if (input.equals("a") || input.equals("b"))
{
System.out.println("You entered: " + input);
return true;
}
else
{
return false;
}
}
A while loop with a break after executing your second print command will limit the code to only asking for a single input.
Scanner ct = new Scanner(System.in);
String input;
System.out.print("Please enter either 'a' or 'b': ");
input = ct.nextLine();
while(input.equals("a") || input.equals("b")){
System.out.println("You entered: " + input);
break;
}
You can also view the problem as generating and processing a stream of strings. The side effects in the generator may trigger some philosophical discussions, otherwise I think it is quite clean:
Stream.generate(() -> {
System.out.print("Enter a letter: ");
return scan.nextLine();
})
.takeWhile(str -> str.equals("a") || str.equals("b"))
.forEach(str -> System.out.println("You entered: " + str));
... which will run like this:
Enter a letter: a
You entered: a
Enter a letter: b
You entered: b
Enter a letter: c
Process finished with exit code 0
Simply
List<Character> expectedChars = new ArrayList<>();
expectedChars.add('a');
expectedChars.add('b');
while(!expectedChars.contains(line = scan.nextLine())) {
System.out.println("Not expected");
}
// Now has a expected char. Proceed.
I without using any break or if-else externally (I am using ternary operator though) within control loop, you can also use below :
Scanner scanner = new Scanner(System.in);
boolean flag=true;
while (flag) {
System.out.println("enter letter");
String bv = scanner.nextLine();
flag=bv.matches("a|b");
System.out.println(flag?"you entered"+bv:' ');
}
with for loop, it can be even simpler :
Scanner scanner = new Scanner(System.in);
for (boolean flag = true; flag;) {
System.out.println("enter letter");
String bv = scanner.nextLine();
flag = bv.matches("a|b");
System.out.println(flag ? "you entered" + bv : ' ');
}
Or if you ok for having whitspace for first run:
Scanner scanner = new Scanner(System.in);
String aa=" ";
String bv=null;
for (boolean flag = true; flag;aa=(flag?"you entered: "+bv:" ")) {
System.out.println(aa);
System.out.println("enter letter");
bv = scanner.nextLine();
flag = bv.matches("a|b");
}
You can easily run a while loop until letter = "a" or letter = "b". Code will start the while loop with intial "" value of the letter and get the new value by scanner. Then it check the new value of the letter before starting the next round of the loop.
package com.company;
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
String letter = "";
while(!(letter.equals("a") || letter.equals("b")))
{
System.out.print("Enter a letter: ");
letter = scan.nextLine();
System.out.println("You entered: " + letter);
}
}
}
Similar as previous answer, but from a code readability perspective i would create an array of valid characters instead and use in condition. That results in the more "text like" condition below reading "if not validCharacters contains letter":
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
List<String> validCharacters = List.of("a", "b");
while (true) {
System.out.print("Enter a letter: ");
String letter = scan.nextLine();
if (!validCharacters.contains(letter)) {
break;
}
System.out.println("You entered: " + letter);
}
}
Your code just needed a little tweak to make it work, although you can use many more efficient approaches but here it is:
import java.util.Scanner;
public class Main
{
public static void main(String[] args)
{
Scanner scan = new Scanner(System.in);
String letter = "a";
while(letter.equals("a") || letter.equals("b"))
{
System.out.print("Enter a letter: ");
letter = scan.nextLine();
System.out.println("You entered: " + letter);
}
}
}

Java:If user type 'y'||'Y' quiz begins,'n'||'N' quiz end.For rest,it shows invalid. I want to show invalid when user type word starting with y or n

I want the program to run only if it recieves 'y','Y','N' or 'n'. It doesn't work for other characters . However when user writes a more than 1 letter word with y or n (for e.g yddh,ndhdh, etc), the program still runs. please suggest what I can do. I tried taking 'a' as String but in if-else statement it showed error because string cannot be compared to char with == operator.
import java.util.Scanner;
class Main {
static char a;
public static void main(String[] args) {
System.out.println("Do you want to play this quiz?");
System.out.println("Type 'Y'for Yes or 'N' for no. It's case Insensitive.");
Scanner sc=new Scanner(System.in);
a=sc.next().trim().charAt(0);
if (a=='n'||a=='N')
{System.out.println("Thanks for downloading!");
System.exit(0);}
else if ((a !='n'&&a !='N') && (a !='y'&& a !='Y'))
{System.out.println("Invalid Syntax");
System.exit(0);}
else if(a=='y'||a=='Y')
{System.out.println("Welcome to the quiz");}
}
}
Further to Subramanian Mariappan's and Yasham's answer, you can shorten the code by using equalsIgnoreCase() method as follows:
import java.util.Scanner;
class Main {
public static void main(String[] args) {
System.out.println("Do you want to play this quiz?");
System.out.println("Type 'Y'for Yes or 'N' for no. It's case Insensitive.");
Scanner sc = new Scanner(System.in);
String userInput = sc.next();
if (userInput.equalsIgnoreCase("N")) {
System.out.println("Thanks for downloading!");
System.exit(0);
} else if (userInput.equalsIgnoreCase("Y")) {
System.out.println("Welcome to the quiz");
} else {
System.out.println("Invalid Syntax");
System.exit(0);
}
}
}

How to stop storing integers and special characters in String in Java?

I wrote a program to read username from keyboard. When I enter any integer or special characters, it is taking that values and displaying on console. But I want that it should not take any integers and special characters. It should take only letters and if any integer or special character is there, then it should give the error message and should not store that value. Can anybody help me with this problem?
The program program which I wrote is
import java.util.Scanner;
public class CheckIsEmpty {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (true) {
System.out.println("Enter User Name:: ");
System.out.println();
String usn = sc.nextLine();
if (usn.trim().isEmpty()) {
System.out.println("Don't Give Space");
System.out.println();
}//if
else if (usn.isEmpty()) {
System.out.println("User Name Is Mandatory");
System.out.println();
} // if
else {
System.out.println("Hi " + usn);
System.out.println("Welcome To Java");
break;
}// else
}//while
}//main
}// class
You can use regex here. If all characters are letters then following code will return true.
usn.matches("[a-zA-Z]+")
If an input string is having any other char it will return false.
Hope it helps.
You can use pattern matching..
boolean b = Pattern.compile("[a-zA-Z]+").matcher(username).matches();

Reversing the words in a sentence using Stack

Does my reverse method only work if I input a series of words all at once?
My task was to: Write a complete method that reads a series of Strings from the user. The user enters "end" to stop inputting words. Then, output the Strings in reverse order of how they were entered. Do not output the String “end”.
Use a stack to accomplish this task. Invoke only the methods push, pop, peek, and isEmpty on the stack object.
Here is how it is supposed to run:
Enter a word or 'end' to quit: Hello
Enter a word or 'end' to quit: Java
Enter a word or 'end' to quit: World
Enter a word or 'end' to quit: end
You entered (in reverse):
World
Java
Hello
But mine runs:
Enter a word or 'end' to quit: Hello
Enter a word or 'end' to quit: Java
Enter a word or 'end' to quit: World
Enter a word or 'end' to quit: end
You entered (in reverse): end
Here is what I have so far:
import java.util.Scanner;
import java.util.Stack;
import java.util.regex.Pattern;
public class Stack1 {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
String input = "end";
do {
System.out.printf("Enter a word or 'end' to quit: ");
input = scanner.nextLine();
if (input == null || input.length() == 0) {
System.out.println("Invalid! Try again...");
return;
}
} while(!input.equalsIgnoreCase("end"));
String reverse = reverse(input);
System.out.printf("You entered (in reverse): %s", reverse);
}
private static String reverse(String inputString) {
String[] str = inputString.trim().split(Pattern.quote(" "));
Stack stack = new Stack();
for(String input : str) {
stack.push(input);
}
StringBuilder builder = new StringBuilder();
while( !stack.isEmpty()) {
builder.append(stack.pop()).append(" ");
}
return builder.toString();
}
}
read input.
push it in stack.
if input equals "end" then stop reading input.
pop stack until stack gets empty.
Code
import java.util.Scanner;
import java.util.Stack;
public class Stack1 {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
String input = "";
Stack stack = new Stack();
while(true){
System.out.printf("Enter a word or 'end' to quit: ");
input = in.next(); // to read a word use next() method.
if(input.equalsIgnoreCase("end")){ break; }
if(!input.equals("")) stack.push(input);
}
System.out.println("You entered (in reverse): ");
while(!stack.isEmpty())
System.out.println(stack.pop());
}
}
Your loop is overwriting input on each iteration. To make it work with your reverse() method, you'll want to concat each word incrementally with a space:
String input = "";
while (true) {
System.out.printf("Enter a word or 'end' to quit: ");
String next = scanner.nextLine();
if (next == null || next.length() == 0) {
System.out.println("Invalid! Try again...");
return;
}
if (next.equalsIgnoreCase("end")) {
break;
}
input += next + " ";
}
Alternatively, you can populate the stack directly in the loop and skip the string splitting:
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
Stack<String> stack = new Stack<>();
while (true) {
System.out.printf("Enter a word or 'end' to quit: ");
String next = scanner.nextLine();
if (next == null || next.length() == 0) {
System.out.println("Invalid! Try again...");
return;
}
if (next.equalsIgnoreCase("end")) {
break;
}
stack.push(next);
}
System.out.println("You entered (in reverse):");
while (!stack.isEmpty()) {
System.out.println(stack.pop());
}
}
Note that the latter solution correctly reverses multi-word inputs, whereas the concatenation approach can't differentiate between lines and words.
This is because your input variable contains only "end". Thus whenever you call reverse function ,it only reverses end String.
String reverse = reverse(input);//input="end"
the problem comes from this place
#Toby Speight thanks for your advice.
by the way I am a English newcomer,I'm pleased to accept any suggestion.
What I'm trying to say is to learn debug your program when you meet problems.In this case: you want the program print a reversed String to the console .but you got a strange answer.now you need to consider where the answer maybe comes from ?
and then just print it before you use it like below
String reverse = reverse(input);//we said you think the problem comes from this place.
System.out.printf("%s%n",input);//this is a key statement to debug--just print it
Now you and then consider where input is not what you want? and then just consider where input comes from?keep on doing this ,and then you can find where
your problem comes from.
On the other hand ,there have a lot of method to debug,you can use IDE debug your program and it will be more efficient ,what's more you can use a log file and so on.
You're using a do-while loop, which is why "end" gets added to the array.
To reverse the string, you can either use a for loop and reverse it yourself:
StringBuilder reverseStr = new StringBuilder();
for (int i = str.size - 1; i >= 0; i--) {
reverseStr.append(str[i]);
}
Or use something like Apache Commons Lang StringUtils.reverse().

Use System.in.read() repeatedly

New to programming, and I'm trying to create a "Guess the letter" game. The idea is that the first person presses a key, then the second person presses a key to see if she has guessed it right.
Here is my code:
package bookExamples;
public class GuessTheLetterGame {
public static void main(String[] args) throws java.io.IOException{
char answer;
System.out.print("press a key and press ENTER:");
answer= (char) System.in.read();
char guess;
System.out.print("Have a guess and press ENTER: ");
guess = (char) System.in.read();
if (guess == answer)
System.out.println("**Right**");
}
}
It runs okay until the line "Have a guess and press ENTER:", then I tried to press a key again, the code has no reaction.
Thank you in advance :)
By casting a System.in.read() to char you are casting a byte from system to UTF-16. Therefore char c = (char) System.in.read(); will only work for very limited input.
I would recommend using Scanner to read in an entire line.
String answer = "A";
Scanner scanner = new Scanner(System.in);
String guess = "";
while(! answer.equalsIgnoreCase(guess))
{
guess = scanner.nextLine();
}
System.out.println("CONGRATULATIONS YOU WON!");
Here's another one that matches original code intent but provides a Scanner and while loop until there is a match
import java.util.Scanner;
public class GuessTheLetterGame {
public static void main(String[] args) throws java.io.IOException{
Scanner keyboard = new Scanner(System.in);
char answer;
char guess;
boolean right = false;
while(!right){
System.out.print("press a key and press ENTER:");
answer= (char) keyboard.next().charAt(0);
System.out.print("Have a guess and press ENTER: ");
guess= (char) keyboard.next().charAt(0);
if (guess == answer){
System.out.println("**Right**");
right = true;
}
}
}
}
I am also learning Java and wanted a way to make this program work using the commands I know (Scanner is more advanced).
As mentioned by Pshemo and Andreas, the System.in buffer has a 'linefeed' character (ASCII 10) still in it (assuming only a single character for 'answer' was entered).
By 'reading' that character the buffer is emptied and the next time System.in.read() is used it will take an entry as expected. I added 'linFed' to clear it.
package BookExamples;
public class GuessTheLetterGame {
public static void main(String[] args) throws java.io.IOException{
char answer;
System.out.print("press a key and press ENTER:");
answer= (char) System.in.read();
char linFed;
linFed= (char) System.in.read();
char guess;
System.out.print("Have a guess and press ENTER: ");
guess = (char) System.in.read();
if (guess == answer)
System.out.println("**Right**");
}}
In your code there is no loop to keep guessing. It's just a one shot deal. To keep guessing, you need to repeat a part of your code.
package bookExamples;
public class GuessTheLetterGame {
public static void main(String[] args) throws java.io.IOException{
char answer;
answer= 'A';
char guess = '\0';
Scanner scanner = new Scanner(System.in);
while(answer != guess) {
System.out.print("Have a guess and press ENTER: ");
guess = scanner.next().charAt(0);
System.out.println(guess);
}
System.out.println("**Right**");
}
If you keep guessing until the answer is right, you no longer need the if statement. The only thing left to keep the formatting correct, is to show the user their guess and start a new line.
NOTE: changed the code to use a scanner, and scanner.next() to get one character at a time.

Categories