How to iterate over ordinal directions over a point (x, y)? - java

I have this function below called findNeighboringChains(i, j). You pass in a point (x, y) and it returns all chain objects that exist in the neighboring points (x + 1, y), (x - 1, y), (x, y + 1), and (x, y - 1). If no chain exists at (x, y) then findChainId(x, y) = -1, else it will return an ID >= 0. Only one chain can exist at each (x, y). For more context, this is a function I am using to find adjacent chains to a cell in the game of Go.
I feel like what I have so far is kind of verbose, but I'm not sure how to make it better. It seems like it would be ideal if I could iterate over those points (x + 1, y) ... (x, y - 1) through a loop. Any suggestions?
public ArrayList<Integer> findNeighboringChains(int i, int j) {
ArrayList<Integer> neighboringChains = new ArrayList<>();
int tmp = findChainId(i - 1, j);
if (tmp != -1) {
neighboringChains.add(tmp);
}
tmp = findChainId(i + 1, j);
if (tmp != -1) {
neighboringChains.add(tmp);
}
tmp = findChainId(i, j - 1);
if (tmp != -1) {
neighboringChains.add(tmp);
}
tmp = findChainId(i, j + 1);
if (tmp != -1) {
neighboringChains.add(tmp);
}
return neighboringChains;
}

One way would be to utilize the Point object that is built into Java, and iterate over a list of points- each time calling the same piece of code. In my solution/refactoring, I create a new method called "getNeighboringPoints(Point p)", which retrieves the four neighboring points. Then, in your function findNeighboringChains, you can iterate using a for-each loop over that list of points.
There are a lot of variations on this kind of pattern you could do, but you're definitely right to think that it's possible to be less redundant. It's always a good idea to try to follow the DRY principle.
public ArrayList<Integer> findNeighboringChains(int i, int j) {
ArrayList<Integer> neighboringChains = new ArrayList<>();
Point p = new Point(i, j);
List<Point> neighboringPoints = getNeighboringPoints(p);
for (Point point : neighboringPoints) {
int tmp = findChainId(point.x, point.y);
if (tmp != -1) {
neighboringChains.add(tmp);
}
}
return neighboringChains;
}
/**
*
* #param p
* The input point.
* #return a list of points neighboring point p
*/
private List<Point> getNeighboringPoints(Point p) {
ArrayList<Point> neighboringPoints = new ArrayList<Point>();
neighboringPoints.add(new Point(p.x - 1, p.y));
neighboringPoints.add(new Point(p.x + 1, p.y));
neighboringPoints.add(new Point(p.x, p.y + 1));
neighboringPoints.add(new Point(p.x, p.y - 1));
return neighboringPoints;
}
One of the benefits of the above method, is now you can later on find that you might need to do another operation on all the neighboring points, and you can reuse the method getNeighboringPoints().
Edit:
Another way to reduce redundancy would be to use the extract method technique.
public ArrayList<Integer> findNeighboringChains(int i, int j) {
ArrayList<Integer> neighboringChains = new ArrayList<>();
int tmp = findChainId(i - 1, j);
checkChain(neighboringChains, tmp);
tmp = findChainId(i + 1, j);
checkChain(neighboringChains, tmp);
tmp = findChainId(i, j - 1);
checkChain(neighboringChains, tmp);
tmp = findChainId(i, j + 1);
checkChain(neighboringChains, tmp);
return neighboringChains;
}
private void checkChain(ArrayList<Integer> neighboringChains, int tmp) {
if (tmp != -1) {
neighboringChains.add(tmp);
}
}
This might be better since it doesn't force usage of the point class on a project which already isn't using points. (It can be annoying when there is one method that uses points where everything else requires the input of two ints).

Related

A* (A Star) - Algorithm | How to go back when there are walls?

I'm currently trying to implement the A* (A star) - Algorithm. I already got it working when I don't have walls and when it is only needed to go besides the wall. My problem now is that when I'm placing the start inside of my walls, my algorithm is calculating infinitely as I think it doesn't go backward. Can you guys please help me?
Here is the code from the node class:
int[][] mMap; // if there is a wall => 1
int[][] mAStarField;
ArrayList<AStarNode> mAStarPath;
public class AStarNode implements Comparable<AStarNode>{
public int x;
public int y;
public float c;
public AStarNode p;
public AStarNode(int x, int y, float c, AStarNode p) {
this.x = x; //X pos
this.y = y; //Y pos
this.c = c; //Cost to get to the node
this.p = p; //Parent of the node
}
//override the compareTo method
public int compareTo(AStarNode node)
{
if (c == node.c)
return 0;
else if (c > node.c)
return 1;
else
return -1;
}
}
public class Node {
public int x;
public int y;
public int z;
public int w;
public Node(int x, int y, int z, int w) {
this.x = x;
this.y = y;
this.z = z;
this.w = w;
}
}
This is the code from my A* algorithm:
//Pathfinding with A*
//return path length
int updateAStar() {
//Needed for drawing:
//Array containing the distance to the start node (filled with max int at start)
mAStarField = new int[mMap.length][mMap[0].length];
//List containing the found path
mAStarPath = new ArrayList<AStarNode>();
for (int j = 0; j < mMap.length; j++) {
for (int k = 0; k < mMap[0].length; k++) {
mAStarField[j][k]=Integer.MAX_VALUE;
}
}
//AStarNode(x,y,c,w)
//x X pos
//y Y pos
//c Cost to get to the node
//p Parent of the node
//List can be sorted expensive but simple by c value with
//Collections.sort(openList);
ArrayList<AStarNode> openList = new ArrayList<AStarNode>();
ArrayList<AStarNode> closedList = new ArrayList<AStarNode>();
int dist = abs(mStartNode[0]-mEndNode[0])+abs(mStartNode[1]-mEndNode[1]);
//If there is any target, that isn't on my field, add start node to list
if (dist>0 && mMap[mStartNode[0]][mStartNode[1]] != 1 && mMap[mEndNode[0]][mEndNode[1]]!=1) {
openList.add(new AStarNode(mStartNode[0], mStartNode[1], 0, null));
mAStarField[mStartNode[0]][mStartNode[1]] = 0;
}
// my code begins here (only everything from here on can be edited!)
while(!openList.isEmpty())
{
Collections.sort(openList);
AStarNode current = openList.get(0);
if(current.x == mEndNode[0] && current.y == mEndNode[1])
{
return 1;
}
openList.remove(0);
closedList.add(current);
ArrayList<AStarNode> neighbors = new ArrayList<AStarNode>();
neighbors.add(new AStarNode(current.x - 1, current.y, current.c + 1, current));
neighbors.add(new AStarNode(current.x + 1, current.y, current.c + 1, current));
neighbors.add(new AStarNode(current.x, current.y - 1, current.c + 1, current));
neighbors.add(new AStarNode(current.x, current.y + 1, current.c + 1, current));
for(AStarNode n : neighbors)
{
if(n.x >= 0 && n.y >= 0 && n.x < mMap.length && n.y < mMap.length && mMap[n.x][n.y] != 1){
float cost = estimateDistanceEnd(n.x, n.y);
n.c = cost;
if(closedList.contains(n) && cost >= n.c) continue;
if(!openList.contains(n) || cost < n.c)
{
n.p = current;
if(!openList.contains(n)){
mAStarField[n.x][n.y] = (int) n.c;
openList.add(n);
Collections.sort(openList);
}
}
}
}
}
return -1;
}
int estimateDistanceEnd(int x, int y){
return abs(x-mEndNode[0])+abs(y-mEndNode[1]);
}
int estimateDistanceStart(AStarNode a){
return abs(a.x-mStartNode[0])+abs(a.y-mStartNode[1]);
}
int estimateDistance(AStarNode a, AStarNode b){
return abs(a.x-b.x)+abs(a.y-b.y);
}
A picture of my current path solving result
Important: I'm only allowed to change code inside of the area I marked.
Thank you!
I can't run the code, but I have a little idea about the the source of the issue. See, the A* algorithm doesn't "walk back" while looking for the best path. It solves the pathfinding issue by calculating the less costly way to get to the end for literally every node that it evaluates. It starts by calculating the itineraries which are the most straightforward, then if it didn't work it'll enlarge it's options until it either, uh, finds a way - or run out of options.
The principle of the closed list to avoid evaluating a node twice. As you guessed, the problem here is that you are creating new nodes for neighbors at every iteration of the pathfinding algorithm, thus making it harder for the closed list to be used correctly.
A complex object like a custom class can be compared through 3 means: it either is the same object (it refer to the same pointer (it's the same instance, it's at the same place in the computer's memory)), or the values are all the same whatever it's pointer is pointing, or you can define a rule to compare them. These methods would be: comparing by reference, comparing by value and operator overloading - although that last one isn't possible in java, but you can write a method to do the same.
When doing closedList.contains(n), you are comparing by reference (which is the default for this kind of operation). Since all the nodes have been created on the fly, even if their coordinates are the same they all have different address in memory, and this is why this condition will never be met.
Assuming that you cannot mess with your tutor's code, you can still fix this. You almost got it right the first time! There are many ways to to fix this, in fact, and as I miss some of the context I'll be rather plain in my suggested approach: you'll write a method to fetch a specific node from a list (like the operator overloading I spoke about, but with the bare minimum effort) and we'll work by reference from this point onward.
First, create a master list of all your AStarNode (if you don't already have one, if you do then use that one instead):
// my code begins here (only everything from here on can be edited!)
ArrayList<AStarNode> nodesList = new ArrayList<AStarNode>();
for (int j = 0; j < mapWidth; j++) {
for (int k = 0; k < mapHeight; k++) {
nodesList.add(new AStarNode(j, k)); // I gimmicked the constructor for my own confort, you'll have to tweak this line so it fits in your code
}
}
Then, write yourself a method which will return a node from an array based on given xy coordinates:
AStarNode GetAStarNodeByPosition(int x, int y, ArrayList<AStarNode> list) {
for (AStarNode m : list) {
if (m.x == x && m.y == y) {
return m;
}
}
return null;
}
Now, you can use these to compare all your nodes by reference. So, now instead of instantiating new nodes all the time, you'll always fetch them from the master list, by reference:
ArrayList<AStarNode> neighbors = new ArrayList<AStarNode>();
neighbors.add(GetAStarNodeByPosition(current.x - 1, current.y, nodesList));
neighbors.add(GetAStarNodeByPosition(current.x + 1, current.y, nodesList));
neighbors.add(GetAStarNodeByPosition(current.x, current.y - 1, nodesList));
neighbors.add(GetAStarNodeByPosition(current.x, current.y + 1, nodesList));
Also, don't forget to fix this line:
//openList.add(new AStarNode(mStartNode[0], mStartNode[1], 0, null));
openList.add(GetAStarNodeByPosition(mStartNode[0], mStartNode[1], nodesList));
Lastly, always remember to test for null if you know that you may have some in your arrays. In this case, the GetAStarNodeByPosition method can return a null if you're too close to the boundaries of the maze. You can either modify the way you add to the neighbors list so there will be no null in there, or you can check for null on this line:
if(n != null && n.x >= 0 && n.y >= 0 && n.x < mMap.length && n.y < mMap.length && mMap[n.x][n.y] != 1){
Honestly I would prevent the inclusion of null in the array at all, that's much safer if you modify the code further later.
Now all your nodes will relate and you'll be able to overcome obstacles which needs your algorithm to search in a more clever way than a straight line.
Have fun!

Find all rectangles in a histogram

I am sure most of you have heard about the largest rectangle in a histogram problem. -Link-
In my current project, I need to change this algorithm so that it finds all rectangles which are not a smaller subset of another rectangle in that histogram.
This is how far I am currently. But I cannot figure out how to not count the subsets in here.
//time: O(n), space:O(n)
public ArrayList<int[]> largestRectangles(int[] height) {
ArrayList<int[]> listRect = new ArrayList<int[]>();
if (height == null || height.length == 0) {
return null;
}
Stack<Integer> stack = new Stack<Integer>();
int max = 0;
int i = 0;
while (i < height.length) {
//push index to stack when the current height is larger than the previous one
if (stack.isEmpty() || height[i] >= height[stack.peek()]) {
stack.push(i);
i++;
} else {
//add rectangle when the current height is less than the previous one
int p = stack.pop();
int h = height[p];
int w = stack.isEmpty() ? i : i - stack.peek() - 1;
listRect.add(new int[]{p,h,w});
}
}
while (!stack.isEmpty()) {
int p = stack.pop();
int h = height[p];
int w = stack.isEmpty() ? i : i - stack.peek() - 1;
listRect.add(new int[]{p,h,w});
}
return listRect;
}
public static void main(String[] args) {
for(int[] rect : largestRectangles(new int[]{1,2,2,3,3,2})) {
System.out.print("pos:"+rect[0]+" height"+rect[1]+"
width"+rect[2]);
System.out.println();
}
}
The idea is to check if the new rectangle being added contains the last added rectangle; if so then simply remove the last added rectangle information from the result list before adding this new one (so confirming by height). I don't have Java IDE handy so tried in C#.
Following is the part you'll need to add in two places (please convert to java) right before your listRect.Add(new[] {p,h,w}.).
if (listRect.Count > 0)
{
if (listRect[listRect.Count - 1][1] <= h)
{
listRect.RemoveAt(listRect.Count - 1);
}
}
This is just an idea. You'll have to write logic for omitting above remove logic for histograms with 0 in them i.e. new int[] { 1, 2, 2, 3, 3, 2, 0, 1 } etc. But logic is similar; you'll have to store a flag etc. and bypass removal of last rectangle based on its position.

How to count a cell's neighbors in a cellular automaton with wraparound

So I'm making a program that simulates Life-like cellular automata, but I'm having some trouble with the method used to count a cell's live neighbors. The problem is that I want to be able to change how the grid wraps around -- that is, whether it wraps around from left to right (i.e., cylindrical), from top to bottom and left to right (i.e., toroidal), or not at all (i.e., flat) -- and I can't figure out how to make my method account for that. Here's what I have so far:
public int getLiveNeighbors(int row, int col)
{
int count = 0;
// "topology" is an int that represents wraparound:
// 0 = flat; 1 = cylindrical; 2 = toroidal
int top = topology != 2 ? row - 1 : (row + ROWS - 1) % ROWS;
int bottom = topology != 2 ? row + 1 : (row + 1) % ROWS;
int left = topology != 0 ? (col + COLS - 1) % COLS : col - 1;
int right = topology != 0 ? (col + 1) % COLS : col + 1;
for (int r = top; r < bottom + 1; r++)
for (int c = left; c < right + 1; c++)
if (!(r == row && c == col) && getCell(r, c).equals(LIVE))
count++;
}
The key, I think, is the if-statement in the for-loop -- there has to be some way to check whether r and c are within the bounds of the grid, while keeping in mind that the definition of "bounds" will vary depending on whether/how the grid wraps around. In the past I've gotten around this by having three different sets (one for each wraparound setting) of eight different if-statements to individually check each of the eight cells comprising the original cell's neighborhood; as you can imagine, it was not very pretty, but at least it worked.
I'm not so great at explaining my own code, so I hope that wasn't too confusing -- I'm feeling a little loopy myself (ha). If anyone has any questions, feel free to ask!
You probably already have a class like Board with a method like getCell(x, y) (at least a method of this kind is present in your code).
I'd just make this method lenient in a sense that it would accept negative x and y or x and y greater or equal to COLS and ROWS. Thus you could just iterate over col - 1 to col + 1 and row - 1 to row + 1 (minus col and row) and not care that these coordinates go "over the board". It's the task of the Board to do coordinate lookups correctly.
What makes your code harder is also that you handle different topologies in one place. It's quite hard to follow.
You could make it simpler by implementing different subclasses of Board like CylindricalBoard, ToroidalBoard and FlatBoard. Each of the subclasses would implement getCell differently, but in the context of the subclass it will be clearly understandable.
You're looking for the Strategy Pattern:
There are common situations when classes differ only in their behavior. For this cases is a good idea to isolate the algorithms in separate classes in order to have the ability to select different algorithms at runtime.
In this case you'd want something like this (abbreviated for clarity):
class Point {
int x;
int y;
}
interface WrapStrategy {
Point moveUp(Point p);
Point moveDown(Point p);
Point moveLeft(Point p);
Point moveRight(Point p);
}
class CylinderWrapping implements WrapStrategy {
int height;
int circumference;
Point moveUp(Point p) {
if (p.y <= 0)
return null; // cannot move up
return new Point(p.x, p.y - 1);
}
Point moveDown(Point p) {
if (p.y >= height - 1)
return null; // cannot move down
return new Point(p.x, p.y + 1);
}
Point moveLeft(Point p) {
if (p.x <= 0)
return new Point(circumference - 1, p.y);
return new Point(p.x - 1, p.y);
}
Point moveRight(Point p) {
if (p.x >= circumference - 1)
return new Point(0, p.y);
return new Point(p.x + 1, p.y);
}
}
Try this:
import java.awt.Point;
public class Neighbours {
public static void main(String[] args) {
Neighbours inst=new Neighbours();
int r=3;//<ROWS
int c=3;//<COLS
for(int i :new int[]{0,1,2}){
inst.type=i;
System.out.format("There are %d neighbours of point (%d,%d), topography type %d\n", inst.countLiveNeighbours(r, c), c, r,i);
}
}
int ROWS=4;
int COLS=4;
int type=0;//0=flat, 1=cylinder, 2=toroid
/**
* Is x,y a neighbour of r,c?
* #return coordinates of neighbour or null
*/
Point neighbour(int x, int y, int r, int c){
if((x==c)&&(y==r))
return null;
switch (type){
/*this is wrong for the reasons explained below
case 0: return ((x<COLS)&&(y<ROWS)) ? new Point (x,y) : null;
case 1: return y<ROWS ? new Point(x%COLS,y) : null;
case 2: return new Point(x%COLS,y%ROWS);
*/
//replacement statements produce the correct behaviour
case 0: return ((x<COLS)&&(x>-1)&&(y<ROWS)&&(y>-1)) ? new Point (x,y) : null;
case 1: return ((y<ROWS)&&(y>-1)) ? new Point(Math.floorMod(x,COLS),y) : null;
case 2: return new Point(Math.floorMod(x,COLS),Math.floorMod(y,ROWS));
}
return null;
}
int countLiveNeighbours(int r, int c){
int result=0;
for(int x=c-1; x<c+2; x++)
for(int y=r-1; y<r+2; y++){
Point p=neighbour(x,y,r,c);
if(live(p)){
System.out.format("\tpoint (%d,%d)\n",(int)p.getX(),(int)p.getY());
result++;
}
}
return result;
}
boolean live(Point p){
boolean result=true;
if(p==null)
return false;
//perform tests for liveness here and set result
return result;
}
}

How to combine and return enum value

I have a coordinate system such as this:
public enum Direction {
N ( 0, 1),
NE ( 1, 1),
E ( 1, 0),
SE ( 1, -1),
S ( 0, -1),
SW (-1, -1),
W (-1, 0),
NW (-1, 1);
private int x = 0, y = 0;
private Direction(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public Direction combine(Direction direction) {
//unsure
}
}
I'm trying to combine directions with a method within the enum, like:
Direction.N.combine(Direction.E) -> should become Direction.NE
Direction.N.combine(Direction.N) -> null or Direction.N again
My thoughts are to loop through all the values in the enum, and find one that matches its x and y combined:
public Direction combine(Direction direction) {
Direction[] directions = Direction.values();
for (int i = 0; i < directions.length; i++)
if (x + direction.x == directions[i].x && y + direction.y == directions[i].y)
return directions[i];
return this;
}
But I feel like that's an inefficient way to approach this. Is there another way to combine these directions that doesn't involve looping through all the enums?
I also want to create an uncombine function that will reverse the combine.
Direction.NE.uncombine() -> Direction[] {Direction.N, Direction.E}
I could also use the same looping technique, like:
public Direction[] uncombine() {
Direction[] directions = Direction.values(),
rtn = new Direction[2];
for (int i = 0; i < directions.length; i++)
if (x == directions[i].x && directions[i].y == 0)
rtn[0] = directions[i];
for (int i = 0; i < directions.length; i++)
if (y == directions[i].y && directions[i].x == 0)
rtn[1] = directions[i];
return rtn;
}
So is there a more efficient way that I could try out?
I think that creating a Map<Direction, Direction> for each enum value is going to give you a good balance between performance and code neatness.
The combine method becomes:
public Direction combine(Direction other) {
return this.combinerMap.get(other);
}
Of course, you need to build the maps during initialization of the enum class.
Returning null from this method is a bad idea because it pushes the responsibility for sanity checking back onto the caller. So I'd write it like this:
public Direction combine(Direction other)
throws InsaneDirectionsException{
Direction res = this.combineMap.get(other);
if (res == null) {
throw new InsaneDirectionsException(
"Can't combine directions " + this +
" and " + other);
}
return res;
}
If your real class is as simply as the one from the question I think that the most efficient way would be to either manually "hardcode" or pre-calculate (e.g. in static init block) the relationship between argument and result and keep it in map and then only refer to already existing results.
You can keep Map<Byte, Map<Byte, Direction>> where x and y will be indexes. Once you compute new x and y, obtaining Direction will be as simple as matrix.get(x).get(y).

Solving Maze with Recursion java

I am trying to find the path to the EndPosition. This is a recursive function. Please help, I'm about to kill myself.
This is the Map given
{ 1, 1, 1, 1 },
{ 0, 0, 1, 0 },
{ 0, 0, 1, 0 },
{ 0, 0, 1, 0 }};
I would like to use the GetPath recursively to get to the EndPosition in the map above. The parameters is the currentPosition, the end position and the map. For this example, the starting position is (0,0) and ending and the EndPosition is (0,3), top right corner. 0's are for walls and 1's are for the path.
I need to return an arraylist filled with the valid points to the Ending Position. Though my array size is always 0 and the base case never returns the path. How can I keep track of the positions in an arraylist?
Please help, would appreciate it
private ArrayList<Point> GetPath(Point CurrentPosition, Point EndPosition, int[][] Map)
{
System.out.println("Current Position: " + CurrentPosition.toString());
ArrayList<Point> p = new ArrayList<Point>();
Path.add(CurrentPosition);
if (CurrentPosition.equals(EndPosition))
{
return Path;
}
Map[(int)CurrentPosition.getX()][(int) CurrentPosition.getY()] = 0; //setting to 0 so my function wont revisit that position in the map
ArrayList<Point> p2 = new ArrayList<Point>(); //Array for the 4 points around the CurrentPosition
p2.add(new Point((int) CurrentPosition.getX(), (int) CurrentPosition.getY()+1));
p2.add(new Point((int) CurrentPosition.getX()+1, (int) CurrentPosition.getY()));
p2.add(new Point((int) CurrentPosition.getX(), (int) CurrentPosition.getY()-1));
p2.add(new Point((int) CurrentPosition.getX()-1, (int) CurrentPosition.getY()));
for (int i = 0; i < p2.size(); i++)
{
int j = 0;
if (((p2.get(i).getX() >= 0 && p2.get(i).getY() >= 0) && (p2.get(i).getX() < Map.length && p2.get(i).getY() < Map[0].length)) && Map[(int) p2.get(i).getX()][(int) p2.get(i).getY()] !=0) //if the points in the array are within range and if the points aren't equal to 0.
{
Map[(int)p2.get(i).getX()][(int)p2.get(i).getY()] = 0;
GetPath(p2.get(i), EndPosition, Map); //recursive method
}
}
return Path;
}
I think I may have found the problem:
You never do anything with the return value of your recursive call:
...
Map[(int)p2.get(i).getX()][(int)p2.get(i).getY()] = 0;
GetPath(p2.get(i), EndPosition, Map); //recursive method
...
You should do the following:
ArrayList<Point> recPath = GetPath(p2.get(i), EndPosition, Map); //recursive method
Path.addAll(recPath);
You actually do need to return Path at the end after all
create a function that takes as parameter the start and end position. have it scan every path it can for clear road. so if you can go north, west, south, east scan those locations for "1". if you find 1, have the function call itself again with the point where you found "1" as the new starting position. pass in the path so far and the targeted end position as well. once one of those finds a match for "1" at the given end position you have reached your path. this may not be optimal path. if you need that, parse all possible paths and pick shortest. in the end traverse your path backward to get all points. since the function gets as argument points visited so far, make sure you dont go to same point again by excluding those from future paths.
public static List<Point> getPath(Point start, Point end, int[][] Map)
{
//Current Position for the currentPosition
// EndPosition, given any point in the map would be the end of the maze
// map is that map that given for example or any other map
// returns an arraylist of positions of the paths
ArrayList<Point> result = new ArrayList<Point>();
boolean solutionExists = buildSolution(start, end, Map, result, new HashSet<Point>());
return solutionExists? result : null;
}
public static boolean buildSolution(Point current, Point end, int[][] map, List<Point> solution, Set<Point> visited) {
visited.add(current);
if (current.equals(end)) {
solution.add(current);
return true;
}
if (map[current.x][current.y] == 0) {
return false;
}
Set<Point> neighbours = getNeighbours(current, map);
neighbours.removeAll(visited);
for (Point neighbour : neighbours) {
ArrayList<Point> temp = new ArrayList<Point>();
Set<Point> tempVisited = new HashSet<Point>(visited);
tempVisited.add(neighbour);
if (buildSolution(neighbour, end, map, temp, tempVisited)) {
solution.add(current);
solution.addAll(temp);
return true;
}
}
return false;
}
public static Set<Point> getNeighbours(Point current, int[][] map) {
int maxX = map.length - 1;
int maxY = map[0].length - 1;
Set<Point> result = new HashSet<Point>();
result.add(new Point(current.x, current.y - 1 < 0 ? current.y :current.y -1));
result.add(new Point(current.x, current.y + 1 > maxY ? current.y : current.y +1));
result.add(new Point(current.x - 1 < 0 ? current.x : current.x -1 , current.y));
result.add(new Point(current.x + 1 > maxX ? current.x : current.x + 1, current.y));
result.remove(current);
return result;
}

Categories