Java StringBuilder with indexOf - java

I'm programming a traditional hangman game in Java. What I'm currently stuck on is to find if the users character input is not a character within the String.
if(getLetters.indexOf(userCharInput)==-1) //getLetters is the StringBuilder, and the userCharInput is a String.
{
playerCounter++;
}
This is the section that I seem to have trouble in, I've looked at different indexOf examples and I've formulated this to work with my program.
The problem is, It doesn't work. I set it so the player has 3 chances to guess the word, since the default word is "apple" I guessed 'a', 'p', and 'l', which leaves 'e' to be guessed. Now I intentionally make 3 incorrect guesses and it doesn't proc the next else if:
else if(playerCounter == 3)
{
System.out.println("All lives are gone! Game Over!");
playerCounter = 1; //resets the playerCounter to one.
System.exit(0);
}
Any help will be greatly appreciated.

It's because when you keep guessing the wrong letter, the first if statement is evaluated to true:
if(getLetters.indexOf(userCharInput)==-1) //getLetters is the StringBuilder, and the userCharInput is a String.
{
playerCounter++;
}
So you keep increasing playerCounter (beyond 3). This means that your next statement is unreachable (once it's greater than 3, it's not going to get any smaller, at least with the code you have posted so far). So else if (playerCounter == 3) may not be reachable.

I guess that your else if is part of another if statement that is getting true, so check that out.

The reason it was not working was because of the indexOf method being used improperly,it was partially because of the ordering of the if statements, but that was very miniscule to the primary issue. What had to be changed was the way I used the indexOf method.
ie. instead of gletter.indexOf(character); it should have been word.indexOf(character);
where word was the word that had to be guessed, and gletter was the StringBuilder used to keep track of user guesses.

Here's the Javadoc for StringBuilder:
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/StringBuilder.html
Based on the code you've posted, I'm guessing:
1) You're saving the letters needed (e.g. the letters in the word "apple") to getLetters.
2) getLetters is type StringBuilder
3) if userCharInput is type "char", then indexOf() probably won't give the expected results
4) Substitute "if" for your "else if"
SUGGESTIONS:
Try changing "getLetters" to a "String", and see if that helps.
while (...) {
...
//getLetters is the StringBuilder, and the userCharInput is a String.
if(getLetters.indexOf(userCharInput)==-1) {
playerCounter++;
}
// Debug: comment this out once it's working
System.out.println ("userCharInput=" + userCharInput + ", playerCounter=" + playerCounter);
if(playerCounter == 3) {
System.out.println("All lives are gone! Game Over!");
playerCounter = 1; //resets the playerCounter to one.
System.exit(0);
}
...
}

Related

How would I create a palindrome checker without if statements

I'm trying to create a programme like this previous one I've made;
It simply gives a boolean true/false on if a string backwards is still spelt the same way.
I've created this using if statements, but would like too know if it is possible too create using only methods and loops, and if so how? I have looked for duplicates, and there are similar posts that achieve what I have below, but everything I find uses if else statements
Any help appreciated as always; thanks.
import java.util.*;
public class testingthingsv24 {
private static Scanner in;
public static void main(String args[])
{
in = new Scanner(System.in);
System.out.println("Please Enter Your String: ");
String n=in.nextLine();
System.out.println("Your String Was: "+n);
StringBuffer str=new StringBuffer(n);
StringBuffer str2=new StringBuffer(str.reverse());
String s2=new String(str2);
System.out.println("Reversed Is: "+str2);
if(n.equals(s2))
System.out.println("ITS A PALINDROME");
else
System.out.println("ITS NOT A PALINDROME");
}
}
Output:
Please Enter Your String:
dad
Your String Was: dad
Reversed Is: dad
ITS A PALINDROME
To test a result, generally a conditional statement (if, ternary or switch) appears useful.
You have to avoid using conditional statements as these conditions are annoying by making your code not readable, brittle, error prone, etc..
To do that, you have to favor abstraction over sequential logic.
In your simple case, you could for example introduce a structure (key-value) that associate each boolean value to the String message.
Map<Boolean, String> messageByBoolean = new HashMap<>();
messageByBoolean.put(true, "ITS A PALINDROME");
messageByBoolean.put(false, "ITS NOT A PALINDROME");
...
System.out.println(messageByBoolean.get(n.equals(s2));
But does it make really sense ? It looks like an overhead as you have just two possibilities.
With 5 or 10 of them, it would make much sense.
would like too know if it is possible too create using only methods and loops, and if so how?
Sure. The if statement is redundant in Java. There are plenty of other conditionals in the language, and there are multiple ways that you could implement the semantics of an if statement (including an else clause, if desired) without actually using an if statement.
For example, you can always replace
if (condition) {
// statements when true ...
} else {
// statements when false ...
}
with
if_replacement: do {
while (condition) {
// statements when true ...
break if_replacement;
}
// statements when false ...
} while (false);
Note that that has no association whatever with any particular problem, and that it uses only looping constructs. A somewhat simpler form is possible if you don't need the analog of an else block. In principle you could replace every if in any program with a construct of this form.
This can't really be achieved any more efficiently (as in using a method or function). The reason is that the if-statement:
if (n.equals(s2))
System.out.println("ITS A PALINDROME");
else
System.out.println("ITS NOT A PALINDROME");
at the processor level would simply evaluate the statement: n.equals(s2) and then switch to the first println if true else go to the second println. If you think about this, there isn't really any optimisation that you can do as this condition will always have to be evaluated and always have to carry out the necessary task (printing).
However, having said that this is the most optimised solution for this part of your code, you can make the code slightly shorted and less bulky without a big if-else.
And to do that, the best solution IMO would be #shmosel's with a ternary expression. This would replace this if-else block with a simple line:
System.out.println(n.equals(s2) ? "ITS A PALINDROME" : "ITS NOT A PALINDROME");
This works due to the general format of a ternary statement:
condition ? task if true : task if false
Can be done with recursion too
boolean isPalindrome (String s) {
return s.length() < 2 ? true : s.charAt(0) == s.charAt(s.length() - 1) && isPalindrome(s.substring(1,s.length() - 1));
}

Java Do While Statement with two conditions

I'm trying to learn java but I'm stuck trying to do a single program which concerns Do While Statement with two conditions. Specifically, I want a method to run until the user write "yes" or "no". Well, down there is my thing, what is wrong with it?
String answerString;
Scanner user_input = new Scanner(System.in);
System.out.println("Do you want a cookie? ");
do{
answerString = user_input.next();
if(answerString.equalsIgnoreCase("yes")){
System.out.println("You want a cookie.");
}else if(answerString.equalsIgnoreCase("no")){
System.out.println("You don't want a cookie.");
}else{
System.out.println("Answer by saying 'yes' or 'no'");
}while(user_input == 'yes' || user_input == 'no');
}
}}
I'd do something similar to Tim's answer. But to do things the way you were trying to do them, you have a lot of problems that need to be fixed:
(1) String literals in Java are surrounded by double quote marks, not single quote marks.
(2) user_input is a Scanner. You can't compare a scanner to a string. You can only compare a String to another String. So you should be using answerString in your comparison, not user_input.
(3) Never use == to compare strings. StackOverflow has 953,235 Java questions, and approximately 826,102 of those involve someone trying to use == to compare strings. (OK, that's a slight exaggeration.) Use the equals method: string1.equals(string2).
(4) When you write a do-while loop, the syntax is do, followed by {, followed by the code in the loop, followed by }, followed by while(condition);. It looks like you put the last } in the wrong place. The } just before the while belongs to the else, so that doesn't count; you need another } before while, not after it.
(5) I think you were trying to write a loop that keeps going if the input isn't yes or no. Instead, you did the opposite: you wrote a loop that keeps going as long as the input is yes or no. Your while condition should look something like
while (!(answerString.equals("yes") || answerString.equals("no")));
[Actually, it should be equalsIgnoreCase to be consistent with the rest of the code.] ! means "not" here, and note that I had to put the whole expression in parentheses after the !, otherwise the ! would have applied only to the first part of the expression. If you're trying to write a loop that does "Loop until blah-blah-blah", you have to write it as "Loop while ! (blah-blah-blah)".
I might opt for a do loop which will continue to take in command line user input until he enters a "yes" or "no" answer, at which point the loop breaks.
do {
answerString = user_input.next();
if ("yes".equalsIgnoreCase(answerString)) {
System.out.println("You want a cookie.");
break;
} else if ("no".equalsIgnoreCase(answerString)) {
System.out.println("You don't want a cookie.");
break;
} else {
System.out.println("Answer by saying 'yes' or 'no'");
}
} while(true);

JAVA: How can a nested do-while loop discard characters from the input buffer?

I'm working my way through Oracle's "Java: A Beginner's Guide" and I am stumped by a subsection about using nested do-while loops. The example given creates a simple guessing game where the user inputs a letter between A and Z. If he guesses correctly the program returns "Right", otherwise additional code is executed and a hint is given -- it either returns "too high" or "too low".
The author states that he is using a nested do-while loop to "discard any other characters in the input buffer".
When I run the program without the nested do-while, whether I input a character greater than the answer that is being searched for or less than the answer that is being searched for, the program always evaluates it as being less than the answer. When I run the program with the nested do-while, the program runs correctly.
My Question:
I don't understand how the nested do-while is affecting the rest of the program. What exactly is the nested do-while doing that the outer do-while isn't?
Here's the code:
class Application {
public static void main(String[] args)
throws java.io.IOException {
char ch, ignore, answer = 'K';
do {
System.out.println("I'm thinking of a number between A and Z");
System.out.println("Can you guess it: ");
ch = (char) System.in.read();
do {
ignore = (char) System.in.read();
} while(ignore != '\n');
if(ch == answer) System.out.println("Right");
else {
System.out.println("Sorry, you're ");
if(ch < answer) System.out.println("too low.");
else System.out.println("too high.");
System.out.println("Try again!\n");
}
} while(answer != ch);
}
}
The inner do-while reads a character, compares it to a newline; if it is not a newline, it reads the next character. If you enter abcde, 'a' will end up in the var ch (due to the read in the outer do loop), bcde will all be discarded, and the newline will terminate the inner loop.
If you want analysis of specific inputs, then provide the inputs.
The inner do-while is used just to be sure that you are reading the first character of the input and no more. Because as you see, it starts reading character by character until it finds '\n', and that's like pressing "Enter". So there the program will stop reading your input (Or maybe better, will clear the buffer for future inputs) and the compared input will be truthful.

How to check if there are double letters in a 4 digit code in Java

The above question might seems vague but it's actually a very simple idea which i can't seem to figure out.
It basically is a 4 digit letter code containing letters from A to F for example: ABDF, BAAF, DBAF etc.
Now I'm trying to do some post input-handling where it must become impossible to enter a letter that is already in the code cause it has to be a unique 4 digit code with no repeating letter. I've been trying to make it work but none of my code seems to work so i'm back to scratch asking you guys for help :)
I hope this is somewhat clear otherwise i'll be happy to clear it up.
Thanks in advance.
Kind of a pseudocode but it would work.
String uniquePass="";
while(uniquePass.length<4){
String userInput=getUserInputChar()
if(uniquePass.contains(userInput))
rejectInputAndNotifyUser
else
uniquePass=uniquePass+userInput
}
public static boolean hasDuplicateChars(String string) {
Set<Character> chars = new HashSet<Character>();
for (char c : string.toCharArray()) {
if (!chars.add(c)) return false;
}
return true;
}
Set is a collection that contains no duplicate elements. We will use add method which returns true if this set did not already contain the specified element.
hasDuplicateChars functions iterates over characters in the input string using toCharArray function and for loop; each character is added to the chars set which is initially empty. If add method returns false it means that we have already encountered same character before. So we return false from our function.
Otherwise input is valid and method returns true.
using this function you'll be able to see if the string contains unique characters
public static boolean checkForUnique(String str){
boolean containsUnique = false;
for(char c : str.toCharArray()){
if(str.indexOf(c) == str.lastIndexOf(c)){
containsUnique = true;
} else {
containsUnique = false;
}
}
return containsUnique;
}
Update:
This will be ran everytime a user enters a character and if it fails, this would mean there is a duplicate. You have the choice of discarding that input or showing an error.
If you're validating the complete input, you can lean on the set semantics, and a few tricks
String s = "ABAF";
int count = new HashSet<>(Arrays.asList(s.split(""))).size();
if (count - 1 == 4) {
System.out.println("All ok");
} else {
System.out.println("Repeated letters");
}
the split("") will split the string to a an array like {"","A", "B", "A", "F"}.
The new HashSet<>(Arrays.asList(s.split(""))) will create a Set with String elements, and as the Set will bounce back the elements already contained, the size of the set for e.g. "AAAF" will be 3 (it'll contain the "", "A" and "F"). This way you can use the size of the set to figure out if all letters of a String are unique
If its while typing you'll than the solution depends on the input method, but you can have something like (pseudo stuff)
if (pass.contains(letter)) {
breakAndNotifyUser();
} else {
pass+=letter;
}

Efficent way to replace underscore with char or string

I have researched this topic for a while, but without much success. I did find the StringBuilder and it works wonders, but that's as far as I got. Here is how I got my hangman program to work like it should:
if(strGuess.equalsIgnoreCase("t")){
mainword.replace(0,1,"T");
gletters.append('T');
}
else if(strGuess.equalsIgnoreCase("e")){
mainword.replace(1,2,"E");
gletters.append('E');
}
else if(strGuess.equalsIgnoreCase("c")){
mainword.replace(2,3,"C");
gletters.append('C');
}
else if(strGuess.equalsIgnoreCase("h")){
mainword.replace(3,4,"H");
gletters.append('H');
}
else if(strGuess.equalsIgnoreCase("n")){
mainword.replace(4,5,"N");
gletters.append('N');
}
else if(strGuess.equalsIgnoreCase("o")){
mainword.replace(5,6,"O");
mainword.replace(7,8,"O");
gletters.append('O');
}
else if(strGuess.equalsIgnoreCase("l")){
mainword.replace(6,7,"L");
gletters.append('L');
}
else if(strGuess.equalsIgnoreCase("g")){
mainword.replace(8,9,"G");
gletters.append('G');
}
else if(strGuess.equalsIgnoreCase("y")){
mainword.replace(9,10,"Y");
gletters.append('Y');
}
else{
JOptionPane.showMessageDialog(null, "Sorry, that wasn't in the word!");
errors++;
gletters.append(strGuess.toUpperCase());
}
SetMain = mainword.toString();
GuessedLetters = gletters.toString();
WordLabel.setText(SetMain);
GuessedLabel.setText(GuessedLetters);
GuessText.setText(null);
GuessText.requestFocusInWindow();
However, I can't do this for EVERY letter for EVERY word, so is there a simple and efficient way to do this? What I want is to have a loop of some sort so that I would only have to use it once for whatever word. So the word could be technology (like it is above) or apple or pickles or christmas or hello or whatever.
I have tried using a for loop, and I feel the answer lies in that. And if someone could explain the charAt() method and how/where to use it, that'd be good. The closest I got to being more efficient is:
for(i = 0; i < GuessWord.length(); i++) {
if (GuessWord.charAt(i) == guess2) {
mainword.replace(i,i,strGuess.toUpperCase());
}
So if you could use that as a basis and go off of it, like fix it? Or tell me something I haven't thought of.
It's a good question. There's clearly repeated code, so how do you replace all that with something reusable. Actually, you can dispense with all of your code.
That whole code block can be replaced by just one line (that works for every word)!
String word = "TECHNOLOGY"; // This is the word the user must guess
mainword = word.replaceAll("[^" + gletters + "]", "_");
This uses replaceAll() with a regex that means "any letter not already guessed" and replaces it with a underscore character "_". Note that Strings are immutable, and the replaceAll() method returns the modified String - it doesn't modify the String called on.
Here's some test code to show it in action:
public static void main(String[] args) {
String word = "TECHNOLOGY"; // what the user must guess
StringBuilder gletters = new StringBuilder("GOTCHA"); // letters guessed
String mainword = word.replaceAll("[^" + gletters + "]", "_");
System.out.println(mainword);
}
Output:
T_CH_O_OG_

Categories

Resources