I am programming a probe that moves through a 2D board in Java. To do this, I have two ArrayLists of Integer that contain the path that the probe has followed. The first ArrayList contains the x-coordinate, and the second one, the y-coordinate. What I would like to do is check whether the next tile of the movement has been visited or not, this is, whether the new x-coord and the new y-coord are in the corresponding ArrayList and share the same position.That way, if the new tile has been visited, I wouldn't move there. How could I possibly do this? I have tried with indexOf and lastIndexOf, but it doesn't work as each coordinate can be repeated an indefinite number of times. I also tried .contains but it didn't work either as I need that it is contained in both arrays in a specific position.
Any help would be appreciated.
First of all Java is object oriented so you should use objects. Why are you storing a coordinate in two separate arrays?
You can define your own type:
class Position implements Comparable<Position> {
public final int x;
public final int y;
Position(int x, int y) { this.x = x; this.y; }
#Override public int compareTo(Position other) { ... }
#Override public boolean equals(Object other) { ... }
#Override public int hashCode() { ... }
}
Then with this you can do whatever you want, for example
Set<Position> visited = new HashSet<Position>();
Map<Position, Integer> visitedWithSpecificPositionInPath = new HashMap<Position, Integer();
and so on.
A pretty messy approach would be to find all indexes of matching x-coordinates and for each index found check whether the y-coordinate for the given index is equal to the y in question.
So given coordinates x, y and array lists visitedX and visitedY you could do something like this:
public static boolean isVisited(int x, int y){
for(int i = 0; i < visitedX.size(), i++){
if(visitedX.get(i) == x){
if(visitedY.get(i) == y){
return true;
}
}
}
return false;
}
But as Jack has mentioned you should reconsider your data structure as looping over the complete x-coordinates list is not very efficient (though you could reduce limits of outer for loop with usage of visitedX.indexOf(x) and visitedX.lastIndexOf(x) ).
Related
I write plugins for Minecraft and often hit a situation where I have to loop through every block in a 3-dimensional space to process the block in some way. For example:
for (int x = minX; x <= maxX; x++) {
for (int y = minY; y <= maxY; y++) {
for (int z = minZ; z <= maxZ; z++) {
// Do something
}
}
}
These kind of loops happen a lot and it struck me that perhaps there was a better way to do it that would make the code more concise but still be as fast to execute. All I really want to do is loop through every coordinate in a 3 dimensional type.
The Bukkit API has such a type - a Vector class that can hold x,y,z. The Vector class has methods such as getBlockX, getBlockY and getBlockZ that return integers. So, I was thinking of creating a utility method like this:
Stream<Vector> getXYZStream(minVector, maxVector)
This would return a stream of all the vectors (x,y,z) values between the min and max vectors given. So then I could do:
getXYZStream(minVector, maxVector).forEach(v -> doSomething);
How can I make a stream of vectors in this regard? If I can code this approach, then I'll measure the difference in performance and see if it makes sense.
Or is there a better way to do this?
Or should I accept these loops are necessary and the best approach?
I found an approach where one can make a stream using a custom iterator, so one could do something like this:
public Stream<Vector> get3dStream(Vector minVector, Vector maxVector) {
Iterator<Vector> it = new CustomIterator(minVector, maxVector);
return StreamSupport.stream(Spliterators.spliteratorUnknownSize(it, Spliterator.DISTINCT), false);
}
class CustomIterator implements Iterator<Vector> {
private Vector minVector;
private Vector maxVector;
BoundingBox b = new BoundingBox();
// constructor
CustomIterator(Vector minVector, Vector maxVector) {
// initialize cursor
this.minVector = minVector;
this.maxVector = maxVector.add(new Vector(1,1,1));
}
// Checks if the next element exists
#Override
public boolean hasNext() {
return !minVector.equals(maxVector);
}
// moves the cursor/iterator to next element
#Override
public Vector next() {
Vector r = minVector;
increment();
return r;
}
private void increment() {
// Increment the vector - this takes a lot of code to do
}
}
However, as you can see, tracking the next() in the custom iterator will require quite a lot of code and comparing to the three for loops is much more complex and likely to be slower. I agree with the comment from kaya3, it could hide some of the looping, but it's not going to be faster, which is 100% a requirement.
I'm developing a game in which there're many classes. The game appears like a grid plane. I have a function which can detect whether a grid consist of any kind of specified class of object. This function return true if the grid contain any one of the specified type of object and return false if there's none.
However, when the number of classes needed to be detected increase, the parameter list can easily become awfully long, does anyone know how can I resolve that problem? Any design pattern would help? Or my design is acceptable in this case?
public boolean sameClass(int x, int y, String... className) {
for (Entity entity : entities) {
if (entity.getX() == x && entity.getY() == y) {
for (String name : className) {
if (name == entity.getClassName()) {
return true;
}
}
}
}
return false;
}
examples of using the method
sameClass(x, y - 1, "Boulder", "Enemy", "Wall")
sameClass(x, y - 1, "Player")
You can send Collection to your method:
Set<String> params = new HashSet("Boulder", "Enemy", "Wall");
boolean result = sameClass(x, y - 1, params);
You can use Builder-like pattern:
boolean result = new Checker(x, y - 1)
.param("Boulder")
.param("Enemy")
.param("Wall")
.check();
Also, if "Boulder", "Enemy", "Wall" are class of unit, it's better to use Enum instead of strings.
=== Example of possible solution ===
public class Checker {
private int x;
private int y;
private Set<Type> params = new HashSet();
// Entity related code here
public Checker(int x, int y) {
this.x = x;
this.y = y;
}
public Checker param(Type type) {
this.params.add(type);
return this;
}
public boolean check() {
for (Entity entity : entities) {
if (entity.getX() == x && entity.getY() == y) {
return params.contains(entity.getType());
}
}
return false;
}
public enum Type {
BOULDER,
ENEMY,
WALL,
PLAYER
}
}
First of all, don't ever try to compare java strings for equality using '==' unless otherwise you are testing for reference equality only. Rather use .equals() method. Read How do I compare strings in Java? to know more on this aspect.
And, for your actual problem, you can use different techniques. I would prefer to send array of Strings as parameter to keep the method call simple.
Implement your method like below:
public boolean sameClass(int x, int y, String[] className) {
for (Entity entity : entities) {
if (entity.getX() == x && entity.getY() == y) {
for (String name : className) {
if (name.equals(entity.getClassName())) {
return true;
}
}
}
}
return false;
}
Then create a class to store all the possible class name check combination you want to check for:
public class ClassNameCollection {
public static final String[] detectMultiple = new String[]{ "Boulder", "Enemy", "Wall" };
public static final String[] detectPlayer = new String[]{ "Player" };
}
When using this method, try something like below:
sameClass(x, y - 1, ClassNameCollection.detectMultiple);
sameClass(x, y - 1, ClassNameCollection.detectPlayer);
This is actually similar to the way you are handling it using var..args but one advantage of using this way I have described is, for a particular purpose (in your case- detecting wall, detecting equipable , etc.) you can create array of strings once and can call the method using that array variable multiple number of times without the need of writing those large number of lists of class names several times.
I have two classses and I wonder why I always get an error when I try to create an object of class "Knoten" in a method of class "Graph".
Class Graph
public class Graph
{
static Knoten[] knotenliste;
public void punktHinzufuegen(int x, int y){
for(int i=0;i<Gui.zaehler;i++){
knotenliste[i]=new Knoten(x,y);
}
}
}
Class Knoten:
public class Knoten{
int xPos;
int yPos;
public Knoten(int x,int y){
xPos=x;
yPos=y;
}
}
Every time I call method punktHinzufuegen I get an error. Thanks for helping..
Your problem is a very easy problem to solve, so I'll give a short explanation/solution.
What your current problem is, is that you are not defining your knotenliste.
You should define it as the following field:
private static Knoten[] knotenliste = new Knoten[Gui.zaehler];
I would suggest that you do not use a static value but start working with either a fixed ArrayList (in order to index your graph points) or a Queue. Both of those can be found on the Java documentation if you're intested in reading about them.
What I would have done is the following:
public class Graph {
private final ArrayList<Knoten> knotenliste = new ArrayList<>(Gui.zaehler);
public void punktHinzufuegen(int x, int y) {
for (int i = 0; i < Gui.zaehler; i++) {
// Keep in mind that the List#add(int index, E element) will
// shift all the elements previously in the array to the right.
knotenliste.add(i, new Knoten(x, y));
}
}
}
With this you do not only stop abusing the static keyword, but you also have a more flexible Collection to save your Knoten in.
You haven't initialized your array and I think you are getting NullPointerException while adding elements. You need to initialize it before adding elements to it
static Knoten[] knotenliste = new Knoten[<SOME_INT_VALUE>];
In My game I created Multidimensional-Array from com.badlogic.gdx.utils.Array Class as the following:
private static final Array<Array<Actor>> ARRAY_COLS = new Array<Array<Actor>>();
Now, In touchDown method from InputListener, How can I get a specific actor from ARRAY_COLS AND it Index? which all I have the known actor event.getTarget(); as the following:
InputListener listener = new InputListener() {
public boolean touchDown(InputEvent event, float x, float y, int pointer, int button) {
return true;
});
EDIT: How Can I get index of this actor?
like that ARRAY_COLS.IndexOf(event.getTarget()); which the target is ARRAY_COLS.get(_col).get(_row); in the previous image case _col == 3; and _row == 4;
Um, event should return the specific actor that was clicked. If not, try setting actor's Touchable status. If it returns the Group actor that contains the one you need, you can always try using Actor#hit(float x, float y, boolean touchable), which takes local actor coordinates and should return an actor in the specific, clicked place. No need to store 2D array of actors, really.
Also, Actor has a setName method. Instead of a 2D array, you can use a ObjectMap<String, Actor> (also a lightweight LibGDX collection), give actors meaningful names and put the actors in the map during their initiation.
If you need a 2D array, you can use setUserObject to store the index values. I'm assuming you create the actor in nested for loops, so you can use a Vector2, Point or a simple class with two int variables storing the loop indexes. Then you can either serialize it to string and use as name or put as the user object and then retrieve it in the listener method.
For example:
public class IntPair { private final int x, y; /* Constructor, getters */ }
// Creation:
for(int x = 0; x < width; x++) {
for(int y = 0; y < height; y++) {
Actor actor = new Actor();
actor.setUserObject(new IntPair(x, y));
}
}
// Accessing index:
IntPair index = (IntPair) actor.getUserObject();
First of all sorry if my English bad, its not my first language..
I'm working on and android app project, that needed to sort ArrayList of an object..so I made this method to deal with that...
Lets say that I have an object of Restaurant that will contain this data:
private String name;
private float distance ;
And I sort it using the value of the variable distance from lowest to highest:
public void sort(RArrayList<RestaurantData> datas) {
RestaurantData tmp = new RestaurantData();
int swapped;
boolean b = true;
while (b) {
swapped = 0;
for (int i = 0; i < datas.size()-1; i++) {
if (datas.get(i).getDistance() > datas.get(i+1).getDistance()) {
tmp = datas.get(i);
datas.set(i, datas.get(i+1));
datas.set(i+1, tmp);
swapped = 1;
System.err.println("Swapped happening");
}
}
if (swapped == 0) {
System.err.println("Swapped end");
break;
}
}
But when i try the program..the result of an ArrayList is still random, is there any problem with my logic to sort the ArrayList of an object..
Please Help...Thankyou..
Why not use the Collections.sort method?
Here's how you could do it in your project:
public void sort(RArrayList<RestaurantData> datas) {
Collections.sort(datas, new Comparator<RestaurantData>() {
#Override
public int compare(RestaurantData lhs, RestaurantData rhs) {
return lhs.getDistance() - rhs.getDistance();
}
});
}
The above solution is a bit "destructive" in the sense that it changes the order of the elements in the original array - datas. If that's fine for you go ahead and use it. Personally I prefer things less destructive and if you have the memory to spare (meaning your array is small) you could consider this solution which copies the array before sorting. It also assumes your RArrayList is an implementation of ArrayList or backed up by it:
public List<RestaurantData> sort(RArrayList<RestaurantData> datas) {
// Create a list with enough capacity for all elements
List<RestaurantData> newList = new RArrayList<RestaurantData>(datas.size());
Collections.copy(newList, datas);
Collections.sort(newList, new Comparator<RestaurantData>() {
#Override
public int compare(RestaurantData lhs, RestaurantData rhs) {
return lhs.getDistance() - rhs.getDistance();
}
});
return newList;
}
Another thing to consider is also to create a single instance of the Comparator used in the method, since this implementation will create one instance per call. Not sure if it's worth it though, because it will also be destroyed quite soon since the scope is local.
Here's the documentation for the Collections api
One last thing, the comparator simply needs to return a value less than 0 if the elements are in the right order, bigger than 0 if they're in the wrong order or 0 if they're the same. Therefore it seems to be that it's enough to simply subtract the distances of each restaurant. However, if this isn't the case, please implement the comparator suiting your needs.