How to detect if coordinate is inside region? - java

I am trying to detect if a player is inside a specific region, I currently store a Region object that contains two variables that I'll be calling cornerOne and cornerTwo, the corners are basically vector variables that contains X, Y, Z, I save all the regions on a MutableSet.
I want to make sure that the new vector I am passing to it is inside the region.
Currently what I tried was:
fun isInRegion(location: Location): Boolean {
return regions.none { inside(location, it.cornerOne, it.cornerTwo) }
}
private fun inside(location: Location, cornerOne: Location, cornerTwo: Location): Boolean {
return (location.x >= cornerOne.x && location.x <= cornerTwo.x) &&
(location.z >= cornerOne.z && location.z <= cornerTwo.z)
}
I am ignoring Y because the region is only horizontal, so I'll be ignoring height.
The way I currently have it, works for the first 3 regions, but as soon as I make a 4th one it stops working completely, detects the first ones but doesn't the other ones.
Is there a better way to do this? I was told a quadtree could be better, but I don't understand how it would work in this situation.
PS: I am tagging Java too because if someone sees it in the Java section I won't mind a Java help either.
Edit:
On the region code I have if (!isValidRegion()) return which will prevent the region from being too small:
fun isValidRegion(): Boolean {
return !(getXSelected() < 5 || getZSelected() < 5)
}
This makes sure that cornerOne.x <= cornerTwo.x and cornerOne.z <= cornerTwo.z.
This is the method to get the selected X, it'll get the X of the final block and subtract from the X of the first block.
private fun getXSelected(): Int {
return abs(finalBlock.x - originBlock.x) + 1
}
Edit 2:
So I changed the inside function to be:
private fun inside(location: Location, cornerOne: Location, cornerTwo: Location): Boolean {
return inBetween(location.x, cornerOne.x, cornerTwo.x) &&
inBetween(location.z, cornerOne.z, cornerTwo.z)
}
private fun inBetween(a: Int, b: Int, c: Int): Boolean {
return (a in b..c) || (a in c..b)
}
And it worked, however I don't know if this would be a good solution, as I don't know if it would be bad for performance if it is called too often.

Change your code in one of two ways:
1) change the definition of inside to be (less preferred):
private fun inside(location: Location, cornerOne: Location, cornerTwo: Location): Boolean {
return (location.x >= Math.min(cornerOne.x, cornerTwo.x) && location.x <= Math.max(cornerOne.x, cornerTwo.x)) &&
(location.z >= Math.min(cornerOne.z, cornerTwo.z) && location.z <= Math.max(cornerOne.z, cornerTwo.z))
}
Or change the way you generate cornerOne and cornerTwo:
2.1) do without the `abs in your generation (you will need more iterations of generation)
2.2) after you generate the initial candidates of corners swap cornerOne xs if their order is not as expected and do the same on the z axis (separately!!)

Related

Java Stream over a list and check if the list contains at list one object with one of three given field values

Given a class Ball (simplified for this question), where I can not change the equals and hashCode method
class Ball {
String color;
//some more fields, getters, setters, equals, hashcode ..
}
and a list of balls, I want to return true if the list contains at least one ball for each color value "RED", "YELLOW" and "GREEN". Example inputs:
List<Ball> first = List.of(
new Ball("RED"),
new Ball("BLUE"),
new Ball("GREEN"),
new Ball("RED"),
new Ball("YELLOW"),
new Ball("RED"));
List<Ball> second = List.of(
new Ball("RED"),
new Ball("BLUE"),
new Ball("GREEN"),
new Ball("RED"));
expected result for first list is true and for second false. For now I have a classic loop and three counter variables:
private static boolean isValidList(final List<Ball> balls) {
int r = 0;
int y = 0;
int g = 0;
for (Ball ball : balls) {
String color = ball.getColor();
if("RED".equals(color)){
r++;
}
else if("YELLOW".equals(color)){
y++;
}
else if("GREEN".equals(color)){
g++;
}
if(r > 0 && y > 0 && g > 0){
break;
}
}
return r > 0 && y > 0 && g > 0;
}
I have tried to refactor it to use streams like below
private static boolean isValidListStreams(final List<Ball> balls) {
long r = balls.stream().filter(ball -> "RED".equals(ball.getColor())).count();
long y = balls.stream().filter(ball -> "YELLOW".equals(ball.getColor())).count();
long g = balls.stream().filter(ball -> "GREEN".equals(ball.getColor())).count();
return r > 0 && y > 0 && g > 0;
}
but the above need to stream over the list 3 times. Is there a way I can do it in one go? I can't do it with filter using or
return balls.stream()
.filter(ball -> ball.getColor().equals("RED") ||
ball.getColor().equals("YELLOW") ||
ball.getColor().equals("GREEN")).count() >= 3;
since there may be multiple of the same color.
I can't do it with filter using or since there may be multiple of the same color.
You can just use distinct to remove the duplicate colours.
Since you cannot modify equals, you should first map everything to their color first, then distinct and filter.
return balls.stream()
.map(Ball::getColor)
.distinct()
.filter(color -> color.equals("RED") ||
color.equals("YELLOW") ||
color.equals("GREEN")).count() == 3;
Notice that your original for loop is short-circuiting - once you have found the three required colours, you stop looping. However, count will count everything. If that is undesirable, you can do a limit(3) before it.
Also, replacing the || chain with Set.of(...).contains could look better if there are many colours that you want to check:
return balls.stream()
.map(Ball::getColor)
.distinct()
.filter(Set.of("RED", "YELLOW", "GREEN")::contains)
.limit(3)
.count() == 3;
Lets make it a fair fight, your original snippet is much, much longer than it needs to be:
boolean r = false, y = false, g = false;
for (Ball ball : balls) {
String color = ball.getColor();
if ("RED".equals(color)) r = true;
if ("YELLOW".equals(color)) y = true;
if ("GREEN".equals(color)) g = true;
if (r && y && g) return true;
}
return false;
Streams don't 'like it' if you have to refer to results of other operations. That's because the stream API tries to cater to way too many scenarios, thus, you get the lowest common denominator. Which, in this case, is parallel processing: Imagine java runs your stream by handing each individual item to a separated out system - now there is no longer such a thing as 'any previous result' or 'have we seen at least 1 red, at least 1 green, and at least 1 yellow ball at this point' - there is no 'this point', there's just the stream itself.
Hence, it's going to either look ugly (because you're using the wrong tool for the job), or, it's fundamentally far more inefficient. It would look something like this:
return balls.stream()
.map(Ball::getColor)
.filter(x -> x.equals("RED") || x.equals("GREEN") || x.equals("YELLOW"))
.distinct()
.count() == 3;
Comparing code lengths its not significantly simpler. It is considerably worse in performance: It needs to do a distinct scan which requires another run through, and must iterate the whole thing, whereas the first snippet will stop the moment it sees the third color.
Trying to smash those back in, you're looking at a real ugly mess. Golfed to as small as I could make it:
boolean[] c = new boolean[4];
return balls.stream()
.map(Ball::getColor)
.peek(x -> c[x.equals("RED") ? 0 : x.equals("YELLOW") ? 1 : x.equals("BLUE") ? 2 : 3] = true)
.anyMatch(x -> c[0] && c[1] && c[2]);
It's not much code but it introduces all sorts of weirdness - it's weird enough that this probably needs commentary to explain what's going on. So not really a 'win'. It certainly isn't going to be any faster than the original.
In general when you are iterating over a collection with the intent to contrast between values and those operations cannot be described in terms of primitives of the list itself (such as .distinct() or .sorted() or .limit) and there is no pre-baked terminal operation (such as .max()) that does what you want, it's rather likely you do not want streams.
You can extract distinct colors (using Stream API), then simply search in the Set.
Set<String> colors = balls.stream().map(Ball::getColor)
.collect(Collectors.toSet());
if (colors.contains("RED") && colors.contains("GREEN") && colors.contains("YELLOW")) {
// test passes ...
}
If required colors are precomputed as a final Set<String>, code can be even more readable by using containsAll (checking if the retrieved set is a superset of the required set):
final Set<String> requiredColors = Set.of("RED", "GREEN", "YELLOW");
Set<String> colors = balls.stream().map(Ball::getColor)
.collect(Collectors.toSet());
if (colors.containsAll(requiredColors)) { /* test passes */ }
In sort my suggestions are:
Don't hard-code values to check against inside the method, provide them as a parameter.
Use enums, don't rely on strings.
Since you're describing the color of each Ball object with a string name (not for instance as a hex-code) implies that you expect only a moderate number of colors to be used in your application.
And you can improve the design of the Ball class by using a custom enum type Color instead of stream. It will guard you from making a typo and also provides a possibility to introduce a useful behavior withing the Color enum and also benefit from various language and JDK features related to enums.
public enum Color {RED, YELLOW, GREEN}
And even you don't consider utilizing enums it worth to change the method signature of the method you've listed by including an aditional parameter - a Set of colors instead of hard-coding them.
Note: there's also an inconsistency between the title and the code you've provided. The title says:
check if the list contains at list one object with one of three
given
However, your code aims checks whether all given values are present.
That's how you can check whether at least one color from the given set is present, as the question title says,:
private static boolean isValidListStreams(final List<Ball> balls, Set<Color> colors) {
return balls.stream()
.map(Ball::getColor)
.anyMatch(colors::contains);
}
But if you need to check if all the given colors are present, you can do it like that:
private static boolean isValidList(final List<Ball> balls, Set<Color> colors) {
return colors.equals(
balls.stream()
.map(Ball::getColor)
.filter(colors::contains)
.limit(colors.size())
.collect(Collectors.toSet())
);
}
main()
public static void main(String[] args) {
List<Ball> balls = // initializing the source list
isValidListStreams(balls, Set.of(Color.RED, Color.GREEN, Color.YELLOW)); // or simply EnumSet.allOf(Color.class) when you need all enum elements instead of enumerating them
}

How do I check an array's bounds and make sure the code does not error in the game "Go" that I am making in Java

protected void pressedOnSpace(int row, int col) {
if (board[row][col] < board[0][0]) {
canvas.errors = false;
}
if (board[row][col] == GoFrame.WHITE) {
board[row][col] = GoFrame.BLACK;
}
else if (board[row][col] == GoFrame.BLACK) {
board[row][col] = GoFrame.EMPTY;
}
else if (board[row][col] == GoFrame.EMPTY) {
board[row][col] = GoFrame.WHITE;
}
}
I am making the game "Go" for a Java assignment. This is a helper method I'm having issues on. The game is based on arrays and loops. The instructions tell me that I am supposed to implement a bound check and there is a boolean variable "canvas.errors" and if it evaluates to true, a big "X" appears over the board, false is there's no "X". I am supposed to do an array bound check to make sure the "X" does not appear but I am unsure how to go about it because everything I have tried continues to produce an "X" when I click on the board outside of the bounds of the array. I know I am supposed to find all the possible ways the program could error and evaluate those ways to "false" with the variable/function but I cant seem to figure it out. The first "if" statement is what I have as of now for the bound checker after a bunch of tries. Any help would be appreciated as I am a newer coder.
I think maybe you just need help structuring your code to perform a very common operation referred to as validation, or in plain English, making sure you handle situations where your user submits invalid information. All you want to do is make sure the X and Y values represent a legitimate cell on your goban so that your code doesn't choke later on when it tries to process an invalid value.
protected void pressedOnSpace(int row, int col) {
if (row >= 0 && row < 20) && (col >= 0 && col < 20) {
// insert your logic for changing color
} else {
// insert your logic for drawing a big fat X over the board
}
}

Java - How shorten if statements using lambda expressions?

First of all, I'm aware that there is a similar questions like this. The answer to that question, however, did not help me.
I have the following code:
boolean result = fields[x][y + 1].getRing().getPlayer() == player || fields[x][y - 1].getRing().getPlayer() == player || fields[x + 1][y].getRing().getPlayer() == player || fields[x - 1][y].getRing().getPlayer() == player
The code is supposed to check if there are any rings of the current player above, under or next to the current field.
I'm trying to make this code more readable by using a lambda expression, but I can't get it right. I'm not sure whether this is even possible, though.
I tried to replace fields[x][y] by a variable field and then have field become fields[x][y+1], fields[x][y-1], fields[x+1][y], fields[x-1][y]
boolean result = field.getRing().getPlayer() == player -> field = {fields[x][y+1], fields[x][y-1], fields[x+1][y], fields[x-1][y]};
But this gives me a syntax error, which I expected, since field = {fields[x][y+1], fields[x][y-1], fields[x+1][y], fields[x-1][y]}; sets field to an array, and does not iterate over that array.
Is there any way I can make this code shorter using lambda expression?
You keep repeating the same condition, on 4 different values. So what you want in fact is to avoid this repetition, and write the condition once. And you want to test if any of the 4 values match the condition. So start by storing the 4 values in a collection:
List<Field> neighbors = Arrays.asList(fields[x + 1][y],
fields[x - 1][y],
fields[x][y + 1],
fields[x][y - 1]);
Then test if any of those values match the condition:
boolean result = neighbors.stream().anyMatch(field -> field.getRing().getPlayer() == player);
This doesn't necessarily make the code faster or shorter, but it makes it more readable, and DRY.
I don't think lambdas will help here. What I think is better is just to introduce some methods so that the code is more readable.
For example, you could make four methods ringAbove, ringBelow, ringRight and ringLeft and that would make the code a little more readable.
boolean result = ringAbove(x,y) || ringBelow(x,y) || ringRight(x,y) || ringLeft(x,y);
Now just implement each method, with a bit of refactoring:
private boolean ringAbove( int x, int y ) {
return ringAt( x+1, y);
}
The other three methods can be implemented similarly.
I don't really understand this code, but lets just assume it works. player will need to be available as a global variable, or you'll need to also pass it as a parameter.
private boolean ringAt( int x, int y ) {
if( x < 0 || y < 0 || x >= fields.length || y >= fields[x].length )
return false;
return fields[x][y].getRing().getPlayer() == player;
}
Here is another "tiny embedded domain specific language" for
dealing with positions and fields. It makes use of Java8 Streams and lambdas.
The method neighborhood
abstracts the idea of the shape of a discrete geometric neighborhood, so
that is becomes very easy to deal with all kind of neighborhoods on the
grid, for example with something like this:
# ### # #
#x# #x# # #
# ### x
# #
# #
You wanted the first case, but in the code below, it would be very easy to
replace the concept of "neighborhood" by the 8-cell neighborhood (second case), or by something even weirder, like for example the allowed moves of a knight in chess (third case).
The method neighboringFields makes use of the stream of the purely geometric positions, performs some additional checks on it (to ensure that you don't leave the game universe), and then enumerates all the fields with their content.
You can then use these streams of fields to quickly check various predicates on them, for example using the allMatch and anyMatch methods, as is shown in the very last method checkRingsInNeighborhood,
so that the unwieldy if-expression collapses to just this:
return neighboringFields(pos).anyMatch(
field -> field.getRing().getPlayer() == player
);
Here is the full code snippet:
import java.util.function.*;
import java.util.stream.*;
class NeighborPositions {
// Mock up implementations of `Ring`, `Player`, and `Position`,
// whatever those things are
public static class Ring {
private Player player;
public Ring(Player player) {
this.player = player;
}
public Player getPlayer() {
return this.player;
}
}
public static class Player {
private final String name;
public Player(String name) {
this.name = name;
}
}
public static class Field {
private final Ring ring;
public Field(Ring ring) {
this.ring = ring;
}
public Ring getRing() {
return this.ring;
}
}
// you probably want to fill it somehow...
public static int DIM_X = 100;
public static int DIM_Y = 42;
public static Field[][] fields = null;
/** Position on a rectangular grid */
public static class Position {
final int x;
final int y;
public Position(int x, int y) {
this.x = x;
this.y = y;
}
}
/** Shortcut for accessing fields at a given position */
public static Field field(Position p) {
return fields[p.x][p.y];
}
/** Generates stream of neighboring positions */
public static Stream<Position> neighborhood(Position pos) {
return Stream.of(
new Position(pos.x + 1, pos.y),
new Position(pos.x - 1, pos.y),
new Position(pos.x, pos.y + 1),
new Position(pos.x, pos.y - 1)
);
}
/** Generates stream of neighboring fields */
public static Stream<Field> neighboringFields(Position pos) {
return neighborhood(pos).
filter(p -> p.x >= 0 && p.x < DIM_X && p.y >= 0 && p.y < DIM_Y).
map(p -> field(p));
}
/** This is the piece of code that you've tried to implement */
public static boolean checkRingsInNeighborhood(Position pos, Player player) {
return neighboringFields(pos).anyMatch(
field -> field.getRing().getPlayer() == player
);
}
}
You obviously shouldn't try to cram everything into a single file and declare it public static, it's just an example.
You could create a BiFunction<Integer, Integer, Player> that, given x and y coordinates, returns a Player:
BiFunction<Integer, Integer, Player> fun = (coordX, coordY) ->
fields[coordX][coordY].getRing().getPlayer();
Now, to check whether a given player's ring is above, under or next to a given pair of coordinates, you could use:
boolean result = List.of(
fun.apply(x, y - 1),
fun.apply(x, y + 1),
fun.apply(x - 1, y),
fun.apply(x + 1, y))
.contains(player);
This uses Java 9's List.of. If you are not in Java 9 yet, just use Arrays.asList.
Besides, it also uses the List.contains method, which checks if a given object belongs to the list by means of the Objects.equals method, which in turn uses the equals method (taking care of nulls). If Player doesn't override equals, then identity equality == will be used as a fallback.

How to assume if a pedestrian crossed an intersection on OSM

I need to validate if a pedestrian crossed an intersection using GPS' readings and findNearestIntersectionOSM calls to get the nearest intersections.
For each response from geoname, i check if the distance between the 2 points is less than a certain threshold and also using the sin function, i check if the angle between the intersection(GeoPoint.BearingTo) and pedestrian's current location flips its sign
Sin(previous location reading) * Sin(Current location read) < 0
Unfortunately, this is insufficient, and i sometimes receive false positives and so on.
Is there a better approach, or anything I'm missing?
Just to make clear, I'm not planning to dive into Image Processing field, but simply use some of OSM's functionality (if possible)
private void OnClosestIntersectionPoint(GeoPoint gPtIntersection) {
int iDistance = mGeoLastKnownPosition.distanceTo(gPtIntersection);
double dbCurrentBearing = mGeoLastKnownPosition.bearingTo(gPtIntersection);
if(mDbLastKnownBearing == null) {
mDbLastKnownBearing = new Double(dbCurrentBearing);
return;
}
boolean bFlippedSignByCrossing = Math.sin(mDbLastKnownBearing) * Math.sin(dbCurrentBearing) < 0;
mDbLastKnownBearing = dbCurrentBearing; // update bearing regardless to what's going to happen
if(bFlippedSignByCrossing && iDistance <= 10 && !HasntMarkIntersectionAsCrossed(gPtIntersection))
MarkAsIntersectionCrossed(mGeoLastKnownIntersection);
}

My pathfinder has problems finding the shortest path

I'm having problems with a pathfinder (it's my first, so that was to be expected) : it doesn't always take the shortest way. For example, if I want to go one square down, the path will be : one square left, one down, one right.
public void getSquares(){
actPath = new String[Map.x][Map.y];
isDone = new boolean[Map.x][Map.y];
squareListener = new SquareListener[Map.x][Map.y];
getSquares2(x,y,0,new String());
}
public void getSquares2(int x, int y, int movesused, String path){
boolean test1 = false;
boolean test2 = false;
test1 = (x < 0 || y < 0 || x > Map.x || y > Map.y);
if(!test1){
test2 = Map.landTile[y][x].masterID != 11;
}
if(movesused <= 6 && (test1 || test2)){
addMoveSquare2(x,y, path);
getSquares2(x+1,y,movesused+1,path+"r");
getSquares2(x,y+1,movesused+1,path+"d");
getSquares2(x,y-1,movesused+1,path+"u");
getSquares2(x-1,y,movesused+1,path+"l");
}
}
public void addMoveSquare2(int x, int y, String path){
if(x >= 0 && y>=0 && x < Map.x && y < Map.y && (actPath[x][y] == null || actPath[x][y].length() > path.length())){
if(squareListener[x][y] == null){
actPath[x][y] = new String();
actPath[x][y] = path;
JLabel square = new JLabel();
square.setBounds(x*16,y*16,16,16);
square.setIcon(moveSquare);
squareListener[x][y] = new SquareListener(x,y,path);
square.addMouseListener(squareListener[x][y]);
Map.cases.add(square);
}
else{
squareListener[x][y].path = path;
}
}
}
SquareListener is a simple MouseListener which print the square's location and the path to it.
Map.x, Map.y are the map size.
getSquares2 is called with the start point, and draw every squares that are 6 moves away, and consider every case with the value "11" as obstacle.
Can you please help me finding what I've done wrong ?
Here is a screenshot of the result :
http://img808.imageshack.us/img808/96/screen.gif
The red squares are the possible goal. The real one will be defined only when the player click on one square (the MouseListener being SquareListener, it's supposed to know the path to take). The houses are the cases with a value of "11", the obstacles.
Your algorithm looks nearly correct. Nearly, because you forget to assign actPath[x][y] when a second path to the node is found, rendering your length check with actPath[x][y] incorrect. You should do:
else{
actPath[x][y] = path;
squareListener[x][y].path = path;
}
Your algorithm also has abominable time complexity, as it will iterate all paths of length 6 (all 4^6 = 4096 of them) instead of the just the shortest ones (6*6 + 5*5 = 61)
For inspiration, I recommend looking at Dijkstra's algorithm (the precursor to A*), which manages to only visit the shortest paths and concludes in O(number of reachable nodes) when path lengths are small integers as it the case here.
You can take a look here at my answer with example code for A-Star, not a direct answer but the code is readable and it points you to a good book that deals (among many other things) path finding. I never did get around to commenting the code...
Not sure what you mean, in the comment for Daniel, by "Thanks for the link, however, I don't have 1 goal but a number of moves, which makes a lot of possible goals."
You might be interested in this tutorial on the A* search algorithm.

Categories

Resources