Proximity checker for a ButtonGrid (like minefield game) - java

I'm writing a code for a treasure hunt game, a grid of buttons and one of them hide the treasure behind it. I want to ad a proximity checker: if the button clicked touch the button with the treasure behind a message appear telling the player that he is near.
This is what i managed to write but i always get a mistake for the arrays going out of bound (this happens because the last row and column aren't surrounded by buttons).
As you can see i put a lot of "if" to contain the chance of goig out of bound but it keeps happening. Any suggestion?

You can use switch-cases here.
switch(grid){
case treasure[x1][y1]:
// your logic
break;
// other cases
default:
// default scenario
}

You need to check the length of the array before you try to access a row beyond it. It appears that you are doing this for values that too low like this:
if (y1 < 0){
y1 = 0;
}
But you need to have a similar check for values that are too high.
Alternatively,
This design could be much cleaner/simpler if you just passed in the X/Y location of the treasure. Instead of the actual JButtons. Then you could just subtract the values to determine if you were close or not.

The way I would do it is to write a function to do the check for a match that also checks for the bounds. For example:
private boolean isTreasureAt(int x, int y) {
if (x<0 || y<0 || x>width || y>height)
return false;
return treasure[x][y]; // need your correct checking logic here
}
Now you can just call isTreasureAt() for whatever co-ordinates you like and its always safe, no need to put range checks everywhere in your code.

Related

How to treat 4 consecutive spaces as a single character?

I have written a TextArea that types 4 consecutive spaces whenever I press a certain key combination (Alt + C in my case), however, I am looking for a way to make the program treat them as if they're a single character, by which I mean that:
the caret's position jumps from one end of the space sequence to the other if it moves towards it
I can only select all of them at once
if I press backspace and the caret is in front of them, all 4 get deleted at once
I've managed to complete the first two tasks by creating a caret position listener, but whenever I try to delete the 4 spaces, I get an IndexOutOfBoundsException error that redirects me to the listener, even though the code for that is written in a key event handler that checks if the key pressed is a backspace.
I'm only going to include the snippets of code that are relevant to the question, as the whole program is quite long:
textarea.caretPositionProperty().addListener((ob, old1, new1) -> {
int oldi = old1.intValue();
int newi = new1.intValue();
if (oldi > newi && oldi > 3 && textarea.getText(oldi - 4, oldi).equals(" "))
textarea.positionCaret(oldi - 4);
if (oldi < newi && oldi < (textarea.getText().length() - 3) && textarea.getText(oldi, oldi + 4).equals(" "))
textarea.positionCaret(oldi + 4);
});
textarea.addEventFilter(KeyEvent.KEY_PRESSED, e -> {
int cp = textarea.getCaretPosition();
if (e.isAltDown() && (e.getCode() == KeyCode.C)) {
// Some other code
textarea.positionCaret(cp + 4);
}
if (e.getCode() == KeyCode.BACK_SPACE && areat.length() > 3)
if (areat.substring(cp - 4, cp).equals(" "))
textarea.setText(areat.substring(0, cp - 4) + areat.substring(cp));
});
To explain the areat variable: at one point, I thought that the problem might be caused by the textarea.getText() function, given that (presumably) it could either refer to the text before or after pressing backspace (e.g. either "Hello!" or "Hello"). Fortunately, I've already written a text property listener for a separate feature of the program, so I tried solving the problem by declaring a global variable (areat) and storing the old text there (which didn't work, needless to say):
textarea.textProperty().addListener((obs, old1, new1) -> {
areat = old1;
areatn = new1;
// Some other code
});
How should I proceed from here? Is there a problem with the event handler or with the caret listener? Or maybe there is a specific method that has all the features mentioned above built-in?
Side note: I would prefer not switching to a JTextArea, as I've never worked with swing elements before.
EDIT: If you're an admin, please don't mark this question as solved, because I'm still looking for better answers, BUT I've managed to fix the issue by storing the new text of the text property listener in a global variable (areatn) instead of the old one, which I've used in both the event handler and the caret listener. Please do let me know if you've found a solution that's less bodged-in than mine.
EDIT 2: As #kleopatra pointed out in the comments, the TextFormatter class is much better equipped for this kind of situation than my listeners are.
You may be able to do this using a NavigationFilter. You would install one by calling the setNavigationFilter() method in JTextComponent. Here's what the JavaDocs say for NavigationFilter:
NavigationFilter can be used to restrict where the cursor can be
positioned. When the default cursor positioning actions attempt to
reposition the cursor they will call into the NavigationFilter,
assuming the JTextComponent has a non-null NavigationFilter set.
In this manner the NavigationFilter can effectively restrict where
the cursor can be positioned. Similarly DefaultCaret will call into
the NavigationFilter when the user is changing the selection to
further restrict where the cursor can be positioned.
You may be able to write a NavigationFilter that doesn't let the cursor be placed inside the four spaces. Typing an arrow key will move the caret across all four spaces, and selections will include the four spaces, so they will behave for the user as a single character. I've done this kind of thing and it's very reliable and isn't very hard.

Connect Four Program using 2D Arrays in Java

These are the specs for the program I need to complete. Could someone please help me!! I really need to get this program done! Will take any help/advice I can get! Thank you all so much!
You must create two programs named Board and ConFour that have the
following criteria:
1) Proper Introduction
2) Comments that accurately describe the program features
3) Board should have one attribute; a two dimensional array of
character values representing the Connect Four game board. Be sure
to include a constructor (without parameters) that instantiates the
2D-array with 6 rows and 7 columns
4) Board should contain at least four methods. The first method should
be setBoard() which adds an empty character value to every position in the board. The second method, setPosition(), should place the character representing a player (X or O) in the column of their choosing. The third method named checkWinner() should check the board to see if there are four of the same character (X or O) in a row, column or either diagonal. Lastly, printBoard(), should print the contents of the board.
5) ConFour should represent the game play. Have the user(s) enter
START to start the game (they should be able to continuously play after each game)
6) Start each turn by printing the board followed by asking the user to
enter the column they want (be sure to alternate players). If the user enters an incorrect column number, make them re-enter. First player to get four in a row, column or either diagonal is the winner.
Here is a little bit of my thoughts:
To start off, try to make algorithms that check for 4 Xs/Os in a row, which should be 4 for each player. You could also just make 4 algorithms that require you to input the number you are checking for. The directions you need to check are horizontal (check array[i][x+1], where i is the constant in the for loop and x is the number you find to be X or O), vertical (check array[x+1][i] ), right-facing diagonal (check array[i+1][x+1] ), and left-facing diagonal (check array[i-1][x-1].
To print the board, just use 2 for loops that print the values of the array.
For the intro, use a bunch of System.out.println() statements.
The entering of coins is the weird part. You have to create height variables (Or a height function) that stores/checks the height of the coins, then places it on top/next to the other coin. Then check if anyone wins and move on the next player. Keep repeating it until someone wins. Warning: Do not use a while loop. They can't check more than one boolean at a time (but you could put a bunch of if(check) {
boolean itsalltrue = true;
}s, too.
Well, that's all that I can think of (I deliberately did not write the code because I would like you write your own). Enjoy!
Is this for a class? Did you literally just copy and paste the assignment? Try spending some time looking through the notes provided for you, or search more specific questions here. Here's an example of a similar question with code:
Simple 2d array java game

Check if a position is clicked using HashMap

I'm writing a simple program and want to know if an approximate position is clicked. I've got a hashmap with the position as key value and want to display a currently invisible object if the user clicks close enough to the position of the object - not just right at it. The position class just holds an x and a y value.
HashMap<Position, Place> places = new HashMap<>(); //Assume this is populated
#Override
class WhatIsHere extends MouseAdapter {
public void mouseClicked(MouseEvent me) {
Place place = places.get(new Position(me.getX(), me.getY()));
if (place != null) {
place.setVisible(true);
} else {
System.out.println("Nothing there");
}
}
}
This bit of code finds the place if you click right on it though I don't know how to look for, say, me.getX()+-10 and find objects in that range.
Do I need to set four ints holding x-10 and x+10 etc. and just loop through all the positions inbetween? It seems awfully dumb to do it that way.
I dislike exercises that require use of a particular collection, regardless of whether it is the best choice. One of the most important things to learn about the collections, and more generally about data structures, is picking which to use for a given job.
However, I understand you have to use HashMap. Here is one way to do it.
Divide the space up into small squares. Identify each square by e.g. the Point at the minimum x and minimum y. Create a HashMap that maps the square that are near at least one of your objects to the list of nearby objects.
To look up a point, calculate the Point identifying the square containing it. Look up that Point in the map. If it is not present, your point is not near any object. If it is present, check your point against each object in the list according to your nearness rules.
For some configurations of your objects, you may be able to ensure that each square is near at most one object. If so, you can replace the list with the object.
You might want to use TreeMap and you would be able to get a sub map which seems to be what you are looking for.

How do I stop certain code from running?

I have a class that "bans" a player, but I don't want that player to be banned if his name is within a string array. I could loop through the length of the array and use booleans, but there has to be an easier way? I saw something that said just put if a condition is met, put return; and it'll stop all code running below that if statement.
Edit: Thanks for all the help! You were all helpful, even if you're one of the people that downvoted this, which is 4 people at least.
You could make a method that checks if the player is in the array of Strings and yes if you use return in a void method the method will just end.
For example
public void returnUsage(int n)
{
if(n==1)
{
return;
}
System.out.println("n doesn't equal 1.");
}
But it would probably be best to use an if and else to skip the code you don't want to run if the condition is not met. http://docs.oracle.com/javase/tutorial/java/nutsandbolts/if.html
An array is the wrong data structure for this task. Add the players to a Set<> allowedPlayers = new HashSet<String>() then use if(allowedPlayers.contains(name)) return; to conditionally exit the method based on whether the name of the player is in the set. The set will remain fast when the number of names gets large. With an array scanning the array will be slow when the array is big.

Constrain numeric value in JTextField to a specific range, with defaults

Not sure how to write this in JAVA...
I need to code that will insert a default value (say 50) if user keys in a value outside of a given range of 10-100 feet. I have it working for errors if blank or non integer is entered or value is outside the range but cannot figure out how to integrate a default.
What I have that works is
JPanel panel1 = new JPanel();
panel1.setLayout(new FlowLayout());
poolLength = new JTextField(10);
panel1.add(new JLabel("Enter the pool's length (ft):"));
panel1.add(poolLength);
What I want to add is something like this
If poolLength <10 or >200 then poolLength = 100
Else this.add(panel1);
The simplest way is to get the text during e.g. an ActionEvent, parse it and reset the text if it's outside the range.
jTextField.addActionListener(new ActionListener() {
#Override
public void actionPerformed(ActionEvent e) {
boolean isValid = true;
try {
int intVal = Integer.parseInt(jTextField.getText());
if (intVal < 10 || intVal > 200) {
isValid = false;
}
} catch (NumberFormatException x) {
// user entered something which is not an int
isValid = false;
}
if (!isValid) {
jTextField.setText("100");
}
}
});
Also see How to Use Text Fields.
Another way would be to use a spinner which does something like this by default.
disclaimer: I do not know Swing well, actually, I dont remember much at all..
Maybe you simply need to attach a validator to your JTextField?
Here you have an example, however please notice that in that post they check for the length of the text, not the contents. But having the text, you can easily parse it as a number and check if it is greater/lower than the bounds.
As you see in that post, by returning true/false you will prevent the user from entering a wrong value - ie. too small. Now, when wrong value is detected, then, instead of returning 'false', maybe it is possible to simply myjtextfield.setText("50.0") on that input? That may do exactly what you wanted.
really, be careful with those "maybe"s: I do not know Swing, but from general UI framework design, trying to "setText" may:
throw an exception: many frameworks think it's quite evil to change the field's value during validation and defend themselves against it
cause strange issues when editing: if that JTextEdit calls validation upon every single change of the text, you will notice odd things when trying to, i.e. select-all, delete, write 123. You'll end up with 50.0123 or 12350.0 as the JTextEdit might try to validate the intermediate empty text after deletion and coerce it to "50.0"..
or, it may just work.
So, if your time is critical, just try it. Maybe I guessed well. But, if you have some time to spare, wait until someone checks that I didn't write any nonsense.
Use a JSpinner instead.
It will not behave exactly as described, but provide a better user experience. The user can adjust the value with the ↑/↓ buttons. If they type a value outside the specified range, it will revert to the last valid value when the field loses focus.

Categories