I am using Java to make an Uno game. I have a method called findCard(String cardname) whose function is to find the card in a hand of cards when the user writes in the name of the card (e.g: “Red 6”) and to return null if it can’t find the card. It works fine when I tried something like:
String card = "Red" + " " + "6";
pHand.findCard(card); // return the card Red 6
However, in the game, I will need the user to write a full command such as “deal Red 6”. Thus, I use StringTokenizer to separate the card’s name from the command:
StringTokenizer scan = new StringTokenizer(input);
String cmd = scan.nextToken(); // = "deal"
String color = scan.nextToken(); // = "Red"
String card = color + " " + scan.nextToken(); // = "Red 6"
What is wrong is when I try pHand.findCard(card); in this scenario, it only returns null no matter what was typed in.
All I know about StringTokenizer is that it can split words in a string so I don't see how these are different. Thus, it would be great if anyone can point out the reason and the solution for this.
The comments already have the solutions really... but to wrap some more advice around it:
Your Problem
You're just missing a space between the color and number.
General Advice
Make sure everything is the same case before comparing (e.g. all lower/upper).
Get rid of white space when handling tokens.
Keep variables separate; card value and card color are both unique and useful, putting them back in one string makes them less useful and harder to use and can introduce errors like yours.
Recommendation
Modify findCard() to take 2 strings, one with the card value and one with the color. Also, if you're using "red 6" as a key in a map or something, either:
Make sure you build "red 6" from "red" and "6" using a function that you use everywhere you do this. That way you can unit test the function and you're sure that you don't add a space in one spot and forget it in another spot. Generally anywhere where you duplicate code, you might mess up - so don't duplicate.
Make "card" a class and override equals and hash code to use both of these values when determining equality. Then you can use card as the key in a map fine.
Also, I kind of agree with the person who said that string spit() would be easier (just because you see it more often in code). But both should work if you're comfortable; so do it your way if you're happy :).
Related
I have a string that needs to be compared to the names that are on the website. So the first thing I do is get the number of rows (because some arrays have more or fewer than 2 people in them) and then put that size into an int. String[] names come from the names that selenium is supposed to find when it goes to the website to execute this statement assertTrue(assertion.getText().contains(names[i-1])); The problem is: if the names do not appear in the order in which they appear in the array it breaks. In other words, if Mick Jagger is in li[1] and Keith Richards is in li[2], everything runs as expected. But if Keith Richards appears in li[1] it breaks. Furthermore, I am supposed to use the assertTrue command to do this. I have tried sorting, pushing whats on the web into a new ArrayList and I keep getting errors. Anyone know a good way to ensure the order isn't important and still use the assertTrue command?
Thanks,
Scott
WebElement assertion = null;
List<WebElement> assignees = driver.findElements(By.xpath(".//*[#id='assignee']/li"));
int count = assignees.size();
String[] names = {"Mick", "Keith"};
for (int i = 1; i < count; i++)
{
assertion = driver.findElement(By.xpath(".//*[#id='assignee']/li["+i+"]"));
assertTrue(assertion.getText().contains(names[i-1]));
If names represents the full string, you can just flip it. Make sure the text in your assertion (probably should be named something like assignee instead of assertion) is contained in your collection:
assertTrue(Arrays.asList(names).contains(assertion.getText());
Let me know if this won't work because a name is actually a subset of the text in assertion and I'll adjust the answer.
If they don't exactly match (which you have indicated they don't), you could use linq in c# to match this. Since you're using java you can use an additional loop. There may be a more efficient way to do this in java that I'm not aware of.
String assigneeText = assertion.getText();
boolean nameFound = false;
for(String name: names)
{
nameFound = assigneeText.contains(name);
if(nameFound)
{
break;
}
}
assertTrue(nameFound, "None of the expected names were found in the following assignee text: " + assigneeText);
I've been searching around and havn't quite found my answer.
At this moment me and along with my group have created a few classes resembling a Bank with Customer and Account and so on.
I've been struggling lately with trying to improve and secure our code by making our variable called "name" only respond to certain inputs.
In this case, I want to make it only possible for the person to enter name as such:
Atleast 2 words = (For the word part I've seen codes where you count towards the white space between but don't know yet what you do about the last word since there wont be a white space)
Max 4 words = ( Same thing here)
No special signs such as ,!%¤"#()=%/'¨. = ( for this, I've read something about "Matcher and pattern" )
Now I'm quite new to Java and I'm not asking for a code from someone, I'm asking for someone to point me in the right directions regarding codes, because alot of what i've seen like the Matcher and pattern are things that you import with downloading utils and stuff but I reckon that it's not needed and there should be a simpler more basic way as I'm not trying to get ahead of myself with copying codes just to get it done.
So yeah, the String "name" is used alot in our main class "Banklogic" where almost every method that adds something has the variable "name" in it, so it's quite important that I get this done.
I hope I was clear enough and any help would be appreciated! I'm gonna put the alarm for 3 hours before school to see what you guys have come up with so I can try and complete the code before our meeting! Thanks alot in advance :)
Since you asked for hints, you can use Regex to add such rules.
For Numbers only:
if(string.matches("[0-9\\W]")
//allow insertion of data else not
As for rules related Word Count:
string.split("\\W") will create an array separated by space character. You can count the number of elements in this array and allow/disallow input based on that.
As for no signs and only letters:
if(string.matches("[a-zA-Z\\W]")
// Allow Input else not
You can use Document Filter to implement these methods. Document filter will only allow text to be entered if you allow it to.
I hope this helped as a hint.
Also, note that \\W is for whitespaces. If you dont want to allow whitespaces, remove that char.
This is the most effective and simple way of doing the task.
EDIT:
This is a Class I wrote a little while ago to achieve such tasks. Just in case if you are interested....
I am trying to use a full id of a block in the getmaterial part of the code below. this does not work any way that i try.
I cannot find any documentation supporting this issue of handling an id which contains a 'colon :' .
Snip: (Example the 5758:6 below does not work and the string name neither.)
emerald.setIngredient('L', Material.getMaterial("5758:6"));
Material.getMaterial(406) //this is expecting an integer so i cannot give it two numbers
Material.getMaterial(406:1) //this fails as is expecting int
Assuming that emerald is a ShapedRecipe object (since you're using the setIngredient(char, Material) method), then you can also use the setIngredient(char, MaterialData) method instead. You could construct the MaterialData object you want using the (deprecated...) MaterialData(int, byte) constructor. Your new code would look like:
emerald.setIngredient('L', new MaterialData(5758, 6));
The colon in the "full id of a block" is just separating the "id" and "data" values. I think this will do what you're looking for, but if not, let me know so I can clarify.
I don't think you're supposed to be dealing with that number colon thing. Instead, if you want to get to, say, the BRICK material, use Material.BRICK or Material.valueOf("BRICK"). If you want to find the name of a Material m, use m.name() which returns a String.
So I am having all types of trouble trying to design/think about how this can be done. To display the idea better, I have something like this:
private String level =
"#########\n"
+ "# ..#\n"
+ "# #\n"
+ "# #\n"
+ "# $ $ #\n"
+ "# #\n"
+ "# # #\n"
+ "#########\n";
And I want to, for example, move the # up.
I want to keep it as simple as possible as it seems Im not able to do this, I thought about several ideas:
If I know the dimension of the String I can treat it as an matrix or vector and simply do math (a 4x4 matrix I can add simply add 6 to the original position (2,2) to be 1 row below)
I can make every line a string so it's somehow easier to move up and down
This would be completly innefficient I think but I could make a single for loop where everything is printed everytime, so everything is "built" every time anything changes.
The thing is that I just don't see how to update the string. I can think of the operations to know what should be moved and where, but I am either missing a concept or knowledge or is the wrong approach because I can't think of a way of translating the concept of: now delete this character in this position, and write this character in this other position.
Worst part is I found 2 (I think) very good examples of code, but still can't see where they are updating the image:
http://zetcode.com/tutorials/javagamestutorial/sokoban/
my 2D game, Sokoban, is working, but I want to know if I improve the design
Consider building a class called Level, which internally may (up to you) represent the level as two-dimensional array of enums, lets call the enum Tile.
The enum then may look like:
public enum Tile {
WALL('#'),
EMPTY(' '),
FEATURE1('.'),
FEATURE2('$'),
FEATURE3('#');
private final char symbol;
private Tile(final char symbol) {
this.symbol = symbol;
}
public char getSymbol() {
return symbol;
}
}
Now you can add methods to the Level that either return the level as a string (looping over the 2-d array and calling getSymbol() and every Tile, or one that directly prints it.
And to answer your question, now you can easily add a method that moves a certain cell up or switches cells, etc.
The answer is not to manipulate Strings, the answer is to think in OOP.
I'm still new to Java and I would like to understand Strings and Arrays so I got this idea of manipulating elements and place them according to my objective. The objective is that there will be Array of Strings "ABBCCCBBAA" and the "AA","BB" must be replaced into "A" , "BA","AB" into CC. "CC","BC" into B. I basically have no idea how to make it happen but I know it must have Arrays of String. Please help
Regular expression can be very handy for you. Code bellow can do, your job with the use of regular expression:
String mainStr = "ABBCCCBBAA";
Pattern p = Pattern.compile("(AA)|(BB)|(BA)|(AB)|(CC)|(BC)");
Matcher m = p.matcher(mainStr);
while (m.find()) {
String matchedStr = m.group(0);
if("AA".equals(matchedStr) || "BB".equals(matchedStr)){
mainStr = mainStr.replaceFirst(matchedStr,"X");
}
else if("BA".equals(matchedStr) || "AB".equals(matchedStr)){
mainStr = mainStr.replaceFirst(matchedStr,"Y");
}
else if("CC".equals(matchedStr) || "BC".equals(matchedStr)){
mainStr = mainStr.replaceFirst(matchedStr,"Z");
}
}
mainStr = mainStr.replaceAll("X","A").replaceAll("Y","CC").replaceAll("Z","B");
System.out.println(mainStr);
Above code will handle your case of multiple occurrence of same pattern in a given string like:
ABBCCCBBAABBBBAA
will generate output:
CCBBAAAAA.
I am assuming that by "array of strings" you mean:
String[] myvariable = new String[number];
myvariable[0] = "ABBCCBBAA";
myvariable[1] = "some_other_string";
If you are new to Java I suggest you read a beginner's book like Head First Java and also look into java documentation; you don't even have to go that far if you are programming with a decent IDE, like Netbeans (thanks to its intelli-sense feature) is a source of documentation for what you seek (meaning that you can look at all the methods available for a string, read what they do, and see if they can help accomplish what you need).
I am assuming (from what you have said) that you want to replace "AA" for "A", and from that result replace "BB" for "BA", and from that result replace "AB" into "CC", and from that result "BC" into "B".
The code I am posting is REAL simple, and it will only work for this particular case (as I have understood it), if you want to create a method that does this for any string, you need to change some things, but I'll leave that to you.
String[] yourArrayOfStrings = new String[1];
yourArrayOfStrings[0] = "ABBCCBBAA";
String resultOfReplacement= yourArrayOfStrings[0].replaceFirst("AA", "A");
System.out.println(resultOfReplacement); //debugging purposes
resultOfReplacement = resultOfReplacement.replaceFirst("BB", "BA");
System.out.println(resultOfReplacement); //debugging purposes
resultOfReplacement = resultOfReplacement.replaceFirst("AB", "CC");
System.out.println(resultOfReplacement); //debugging purposes
resultOfReplacement = resultOfReplacement.replaceFirst("BC", "BB");
System.out.println(resultOfReplacement); //debugging purposes
The only reason why I created a String[] was because that's what you stated in your question, otherwise I would have simple created a String variable like I did with resultOfReplacement. To access the first element in an array you do arrayVariable[index]. Here I use the replaceFirst function that comes with Java for variables of type String. If you look the method up, it'll tell you that it will look for the first match of the first parameter and replace it with the second parameter.
The System.out.println I have added are for debugging purposes, so you can see on the console what is clearly happening with each replacement. So, the first time I call replaceFirst(...) on the original string which is a[0].
This will happen:
The method will look in "ABBCCBBAA" for the FIRST AND ONLY THE FIRST time "AA" appears and replace it with "A". The result is "return" and you must assign it to a variable if you want access to it to do more actions upon it. In this case, I assign it to a new String variable. You could have just assigned back to a[0], which is likely what you want. (You'd do so like this: a[0]=ourArrayOfStrings[0].replaceFirst("AA", "A");)
For the second replacement, the method will look in "ABBCCBBA" for the first time "BB" appears and replace it for "BA".
See the pattern? This is just a start, and depending on what you want you might need other methods like replaceAll().
Most IDEs will tell you what methods are available for a variable when you access it via ".", so that when you are typing " variablename. " right at that moment a list of methods available for it should appear, if they don´t you can go ahead and do a shortcut like ctrl+space for it to appear and navigate through the methods via the arrow keys so you can read what they do (at least for Eclpise and Netbeans, while programming in Java, it works). Documentation is power!