Programming test on algorithms? [closed] - java
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I was given this question in a programming test for an IT company.
I will try my best to explain it.
The problem is as follows:
Given an Ant at origin (0,0) which moves only in clockwise direction( takes only right turns) on a given path array. so for example if the path array is {2,3,4,5,7} the ant moves 2 units left, then moves 3 units down , then moves 4 units right, then moves 5 units up and then 7 units left so on and so forth.
So write a code which displays the ant's final position(coordinates) and state if the ant intersects it's path in the format:
Ant: (x1,y1) :(yes / no)
for example:
(1) array={1,6,3,5,4}
output: Ant: (2,-1) :yes
showing it graphically
(0, 0)__(1,0)
|
(-2,-1) __ __ __ __(2,-1)
| |
| |
| |
| |
| |
(-2,-6) __ __ __ (1,-6)
here the ant is intersecting its path at (1,-1)
(2) array={2,2,2,1}
output: Ant: (0,-1) :no
showing it graphically
(0, 0)__ __(2,0)
.(0,-1) |
| |
(0,-2)__ __(2,-2)
here the ant doesn't intersect its path.
I wrote a code to find the final position:
public class Ant {
static void findAnt(int arr[])
{
int count = 0;
int x=0,y=0;
for(int element: arr){
if(count>3)
count = 0;
switch(count++){
case 0: x=x+element;
break;
case 1: y=y-element;
break;
case 2: x=x-element;
break;
case 3: y=y+element;
break;
}
}
System.out.println("Ant: "+x+" "+y);
}
public static void main(String[] args)
{
int arr[] = new int[]{2,2,2,1};
findAnt(arr);
}
}
However I cannot devise an algorithm that shows if the ant intersects or not.
Please advise.
It will horizontally intersect if arr[1] <= arr[3] and vertically if arr[0] <= arr[2] you just need to check these positions.
for (int i = 0; i < arr.length; i++){
if (i == arr.length-2)
return false;//prevents indexoutofbounds
if (arr[i] <= arr[i+2])
return true;//intersects
}
this should check to see if p0 is less than p2, p1, is less than p3, and p2 is less than p4, and so on.
boolean intersect = false;
for (int i = 0; i < arr.length; i++){
if (arr[i] == arr[arr.length-2]){//i changed this
intersect = false;//prevents indexoutofbounds
break;
}
if (arr[i] <= arr[i+2])
intersect = true;//intersects
break;
}
and then print out intersect
One solution that doesn't keep a grid in memory, is to keep a set of visited locations in memory. This has the advantage that you don't need to know the boundary of the ant's potential path in advance. Whether it takes more or less memory than a grid, depends on the size of the grid, and the length of the ant's journey.
public class VisitedTileLog {
Set visitedTiles = new HashSet<Coordinates>();
boolean hasIntersected = false;
public void logVisit(Coordinates c) {
if(! visitedTiles.add(c)) {
hasIntersected = true;
}
}
public boolean hasIntersected() {
return hasIntersected;
}
}
Of course you need a Coordinates class with equals() and hashCode():
public class Coordinates {
private int x,y;
public Coordinates(int x, int y) {
this.x = x;
this.y = y;
}
public boolean equals(Object o) {
// Let your IDE write this, or read up on best practice.
}
public int hashCode() {
// Let your IDE write this, or read up on best practice.
}
// Examples of other methods this might have...
public int getX() { ... }
public int getY() { ... }
public Coordinates move(int distance, Direction direction);
}
Now you can take your ant for a walk, and each time it moves, update hasIntersected:
VisitedTileLog log = new VisitedTileLog();
for(int distance : distances) {
...
log.logVisit(...);
...
}
This class could be enhanced with convenience methods that log a whole step's line -- logVisit(Coordinates from, Coordinates to) or logVisit(Coordinates start, int distance, CompassPoint direction).
Depending on the interviewer, a solution like this might get you extra credit for being object-oriented. Indeed, this class could be enhanced to solve the whole of the problem, if it also maintained a currentPosition field.
One way to achieve this is to draw the line during each move for reference. And check before every move that if it is encountering the same coordinate that is already drawn. Below is the code for this approach. You can definitely fine tune it , but here is one way to tackle it.
Steps :
Create Coordinate type to store coordinates.
Create Ant that can hold :
current coordinate: this will hold the Ant Current Coordinate at any time
Direction to Move next : right , left , up or down
data set to keep track of traversed coordinate
data structure to hold all coordinates that are revisited
Now on every move of ant, it knows what direction to move next. And in each move , we draw all coordinates in between the current coordinate and the end point , and store them in traversed coordinate set. If there is hit, we store it in intersected coordinate set instead.
At the end, current coordinate of ant gives us the final coordinate and the line crosses over if the intersected set is not empty.
Here is the long code , that I assume is working fine.
public class PathCross {
public static void main(String[] args) {
int[] movementArray = { 2, 2, 2, 1 };// {1,6,3,5,4};
PathCross driver = new PathCross();
Ant ant = driver.new Ant();
for (int i : movementArray) {
ant.move(i);
}
System.out.println("Ant: (" + ant.currentCoordinate.getX() + "," + ant.getCurrentCoordinate().getY() + ") :"
+ !ant.getIntersectingCoordinates().isEmpty());
}
class Ant {
Coordinate currentCoordinate = new Coordinate(0, 0);
Direction nextDirection = Direction.RIGHT;
Set<Coordinate> intersectingCoordinates = new HashSet<>();
Set<Coordinate> traversedCoordinateSet = new HashSet<>();
public Ant() {
traversedCoordinateSet.add(new Coordinate(0, 0));
}
public Coordinate getCurrentCoordinate() {
return currentCoordinate;
}
public void setCurrentCoordinate(Coordinate currentCoordinate) {
this.currentCoordinate = currentCoordinate;
}
public Direction getNextDirection() {
return nextDirection;
}
public void setNextDirection(Direction nextDirection) {
this.nextDirection = nextDirection;
}
public Set<Coordinate> getIntersectingCoordinates() {
return intersectingCoordinates;
}
public void setIntersectingCoordinates(Set<Coordinate> intersectingCoordinates) {
this.intersectingCoordinates = intersectingCoordinates;
}
public Set<Coordinate> getTraversedCoordinateSet() {
return traversedCoordinateSet;
}
public void setTraversedCoordinateSet(Set<Coordinate> traversedCoordinateSet) {
this.traversedCoordinateSet = traversedCoordinateSet;
}
public void move(int distance) {
Coordinate newCoordinate = null;
switch (nextDirection) {
case RIGHT:
newCoordinate = new Coordinate(currentCoordinate.getX() + distance, currentCoordinate.getY());
for (int i = currentCoordinate.getX() + 1; i <= (currentCoordinate.getX() + distance); i++) {
if (!traversedCoordinateSet.add(new Coordinate(i, currentCoordinate.getY()))) {
intersectingCoordinates.add(new Coordinate(i, currentCoordinate.getY()));
}
}
nextDirection = Direction.DOWN;
break;
case DOWN:
newCoordinate = new Coordinate(currentCoordinate.getX(), currentCoordinate.getY() - distance);
for (int i = currentCoordinate.getY() - 1; i >= (currentCoordinate.getY() - distance); i--) {
if (!traversedCoordinateSet.add(new Coordinate(currentCoordinate.getX(), i))) {
intersectingCoordinates.add(new Coordinate(currentCoordinate.getX(), i));
}
}
nextDirection = Direction.LEFT;
break;
case LEFT:
newCoordinate = new Coordinate(currentCoordinate.getX() - distance, currentCoordinate.getY());
for (int i = currentCoordinate.getX() - 1; i >= (currentCoordinate.getX() - distance); i--) {
if (!traversedCoordinateSet.add(new Coordinate(i, currentCoordinate.getY()))) {
intersectingCoordinates.add(new Coordinate(i, currentCoordinate.getY()));
}
}
nextDirection = Direction.UP;
break;
case UP:
newCoordinate = new Coordinate(currentCoordinate.getX(), currentCoordinate.getY() + distance);
for (int i = currentCoordinate.getY() + 1; i <= (currentCoordinate.getY() + distance); i++) {
if (!traversedCoordinateSet.add(new Coordinate(currentCoordinate.getX(), i))) {
intersectingCoordinates.add(new Coordinate(i, currentCoordinate.getY()));
}
}
nextDirection = Direction.RIGHT;
break;
default:
System.err.println("ERRor");
}
this.currentCoordinate = newCoordinate;
}
}
enum Direction {
LEFT, DOWN, RIGHT, UP;
}
class Coordinate {
int x;
int y;
public Coordinate() {
}
public Coordinate(int x, int y) {
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
#Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + getOuterType().hashCode();
result = prime * result + x;
result = prime * result + y;
return result;
}
#Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Coordinate other = (Coordinate) obj;
if (!getOuterType().equals(other.getOuterType()))
return false;
if (x != other.x)
return false;
if (y != other.y)
return false;
return true;
}
private PathCross getOuterType() {
return PathCross.this;
}
#Override
public String toString() {
return "x=" + x + ", y=" + y;
}
}
}
The problem is hard to find out whether it intersect the previous paths. I create a boolean to record whether it is increase the circle or not. if it is always increasing, it will not intersect the previous paths. If it change to the decreasing, once it began to increasing again, it will intersects the paths. Otherwise, it will not intersects the path
def ant(arr):
length = len(arr)
x = sum(arr[::4]) - sum(arr[2:][::4])
y = sum(arr[3:][::4]) - sum(arr[1:][::4])
if length < 4:
return x, y, False
t1, (t2, t3, t4) = 0, arr[:3]
increase = (t2 < t4)
for i in xrange(3, length):
t5 = arr[i]
if increase and t3 >= t5:
if t1 + t5 - t3 < 0 or i+1 < length and arr[i+1] + t2 - t4 < 0:
increase = False
elif i + 1 < length:
return x, y, True
elif not increase and t3 <= t5:
return x, y, True
t1, t2, t3, t4 = t2, t3, t4, t5
return x, y, False
Related
Method to find if a snake in a snake game has made a loop
I am relatively new to java, and I have an idea for a mechanic I want to implement in to my game. However, I have no idea how to go about solving this problem. My snake game works on a basic coordinate system. I want it to be so that when the snake makes a closed loop (a rectangle or square) the game will detect it has made a loop. I have tried writing a method to locate the part of the snake's body that is the most upper-left, and then checking from there, but it seems to not work very well. Here is the method I attempted to write, if It helps at all. Thank you for any help!! public boolean checkRing() { int topLeftX = 5000; int topLeftY = 5000; for(int i = bodyParts;i>0;i--) { // Finds coordinates of top left box if(x[i] < topLeftX) { topLeftX = x[i]; } if(y[i] < topLeftY) { topLeftY = y[i]; } } // Use isBody() method below (not bug tested) to check for rectangle boolean lineFoundVert = false; int checkingX = topLeftX; int checkingY = topLeftY; int vertCounter = 1; while(!lineFoundVert) { if(isBody(checkingX, checkingY)) { vertCounter++; checkingX++; } else lineFoundVert = true; } boolean lineFoundHori = false; checkingX = topLeftX; checkingY = topLeftY; int horiCounter = 1; while(!lineFoundHori) { if(isBody(checkingX, checkingY)) { horiCounter++; checkingY++; } else lineFoundHori = true; } debug1X = topLeftX + 1; debug1Y = topLeftY + vertCounter; debug2X = topLeftX + horiCounter; debug2Y = topLeftY + 1; if(isBody(topLeftX + 1, topLeftY + vertCounter) && isBody(topLeftX + horiCounter, topLeftY + 1)) { return true; } return false; }```
Here is an approximate solution: private boolean isEdgeCoordinate(Coordinate[] bodyparts, int index) { // for every bodypart check that its neighbours (bodypart one before and // bodypart one after) dont share X axis and dont share Y axis. As long // as that is the case it is an edge. //additionally for the last bodypart you needto check that it has first // bodypart as a neighbour and check them as neighbours otherwise no // rectangle to begin with } using this method check the amount of edges in your bodyparts array. If the total number of edges == 4 you have got a square/rectangle
Java - Last created object overwrites previous one
I am working on a dungeon styled game project and am using a 2D array to create the layout of the rooms. I am using a map generation class and a point class in order to create the map and keep track of which room is being accessed. A starting point is chosen upon generation (usually just 0,0 being the center of the 2D array) and the point for the boss (which is created but not filled). The map generation itself works fine but for some reason my starting point is being overwritten by the boss point. I've tried having the starting point just being defaulted to (0,0) and that didn't work. I tried forcing the boss point to also be (0,0) to start and that resulted in a null pointer exception. I am not sure why this is occurring and would appreciate a bit of help. MapGeneration Class /********************************************** * created by Intellij idea. * User: Kyle Castillo * Date: 2/14/2020 * Time: 10:41 AM * Contact: kylea.castillo#calbaptist.edu ***********************************************/ import java.util.Random; import java.util.Vector; public class MapGeneration { private static Vector<Vector<Integer>> map; private Point startPnt; private Point bossPoint; private static Integer size; /************************************************************ * Constructor class for Map Generation * The Size will always be an X by X square based on size * Starting Point is specified by the starting (x,y) * Rooms are designated by a numerical value * - A 0, indicating an empty space * - A 1, indicating a filled space with a room * - An 8, indicating the array boundary. ************************************************************/ MapGeneration(int size, int startX, int startY) { startPnt = new Point(startX,startY); bossPoint = new Point(); MapGeneration.size = size + 2; //the additional two is to account for boundaries map = new Vector<>(); //Check to prevent the creation of an array where the starting x and y are outside of the array bounds. if (startX == 0 || startX == size - 1 || startX == size) throw new IllegalArgumentException("Error, the starting X value " + startX + " is not allowed!"); if (startY == 0 || startY == size - 1 || startY == size) throw new IllegalArgumentException("Error, the starting Y value " + startY + " is not allowed!"); //Creation of the starting room layout. for (int row = 0; row < size; row++) { Vector<Integer> tmp = new Vector<>(); for (int col = 0; col < size; col++) { //The first row, the first value of each row, the last value of each row, and the last row must be 8 //to prevent the generation later from going out of the 2D array boundary. if (row == 0 || col == 0 || row == size - 1 || col == size - 1 ){ tmp.add(8); //If the row and col match the starting value then this is the first room. } else if (row == startY && col == startX){ tmp.add(1); } else { //Empty space that can be filled with a room. tmp.add(0); } } map.add(tmp); } } /********************************************************************************* * The generate map populates the map based on the desired number of rooms. * The number of rooms cannot exceed the maximum space available within the map. * If the number of rooms fits then the map is generated from the starting point. *********************************************************************************/ public void generateMap(int numRooms) { //Checking to make sure that the number of rooms does not exceed the total number of empty spaces. if (numRooms > ((map.size() - 2) * (map.get(0).size() - 2))) { throw new IllegalArgumentException("Error, room amount exceeds map space!"); } int x = startPnt.getX(); int y = startPnt.getY(); Point crntPnt = new Point(x,y); bossPoint = crntPnt; //Based a random number 0-3 a direction is chosen to create a new room. Random randDirection = new Random(); int compass; while (numRooms != 0) { compass = randDirection.nextInt(4); switch (compass) { case 0: //Compass Index is North, indicates a shift in ROW + 1 int nextPos = map.get(crntPnt.getY() + 1).get(crntPnt.getX()); if(nextPos == 8){ //do nothing, its the map boundary } //As long as the next spot isn't already filled, create a room else if (nextPos != 1) { map.get(crntPnt.getY() + 1).set(crntPnt.getX(),1); crntPnt.setY(crntPnt.getY() + 1); //If the current point is further from the start point then make the boss point the current point if (bossPoint.distance(startPnt) < crntPnt.distance(startPnt)) bossPoint = crntPnt; numRooms--; //If the next position is 1 move the current position but do not fill the spot or //decrease the number of rooms left to make. } else if (nextPos == 1) { crntPnt.setY(crntPnt.getY() + 1); } break; /**************************************** * The rest of the cases function the exact * same way as the first. ****************************************/ case 1: //Compass Index is East, indicates a shift in COL + 1 nextPos = map.get(crntPnt.getY()).get(crntPnt.getX() + 1); if(nextPos == 8){ //do nothing } if (nextPos != 1) { map.get(crntPnt.getY()).set(crntPnt.getX() + 1,1); crntPnt.setX(crntPnt.getX() + 1); if (bossPoint.distance(startPnt) > crntPnt.distance(startPnt)) bossPoint = crntPnt; numRooms--; } else if (nextPos == 1) { crntPnt.setX(crntPnt.getX() + 1); } break; case 2: //Compass Index is South, indicates a shift in ROW - 1 nextPos = map.get(crntPnt.getY() - 1).get(crntPnt.getX()); if(nextPos == 8){ //do nothing } if (nextPos != 1) { map.get(crntPnt.getY() - 1).set(crntPnt.getX(),1); crntPnt.setY(crntPnt.getY() - 1); if (bossPoint.distance(startPnt) > crntPnt.distance(startPnt)) bossPoint = crntPnt; numRooms--; } else if (nextPos == 1) { crntPnt.setY(crntPnt.getY() - 1); } break; case 3: //Compass Index is West, indicates a shift in COL - 1 nextPos = map.get(crntPnt.getY()).get(crntPnt.getX() - 1); if(nextPos == 8){ //do nothing } if (nextPos != 1) { map.get(crntPnt.getY()).set(crntPnt.getX() - 1,1); crntPnt.setX(crntPnt.getX() - 1); if (bossPoint.distance(startPnt) > crntPnt.distance(startPnt)) bossPoint = crntPnt; numRooms--; } else if (nextPos == 1) { crntPnt.setX(crntPnt.getX() - 1); } break; } } map.get(bossPoint.getY()).set(bossPoint.getX(),2); } #Override public String toString() { int sizeTemp = map.get(0).size(); for (int row = 0; row < sizeTemp; row++) { System.out.print("[ "); for (int col = 0; col < sizeTemp; col++) { int type = map.get(row).get(col); System.out.print(type + " "); } System.out.print("]\n"); } return ""; } public static void main(String[] args) { MapGeneration map = new MapGeneration(11, 5, 5); System.out.println("Empty Map:"); System.out.println(map); System.out.println("Starting point prior to map generation: " + map.startPnt); map.generateMap(10); System.out.println(map); System.out.println("The starting room is at " + map.startPnt); System.out.println("The boss room is at " + map.bossPoint); System.out.println("The distance to the boss room is: " + (int) map.startPnt.distance(map.bossPoint)); } } Point Class /********************************************** * created by Intellij idea. * User: Kyle Castillo * Date: 3/4/2020 * Time: 9:04 AM * Contact: kylea.castillo#calbaptist.edu ***********************************************/ public class Point { private static int x; private static int y; Point(){ //default constructor } Point(int x, int y){ this.x = x; this.y = y; } public static int getX(){ return x; } public static int getY(){ return y; } public void setX(int x){ this.x = x; } public void setY(int y){ this.y = y; } public static double distance(Point b){ int bX = b.getX(); int bY = b.getY(); return Math.sqrt((Math.pow((bX - getX()),2.0) + Math.pow( bY - getY(), 2.0))); } #Override public String toString(){ return "(" + getX() + ", " + getY() + ")"; } }
Welcome to Stack Overflow. Your mistake in the code is, x and y variables are marked static in Point class. Then they will be class variables, not instance variables. Eventhough you create a new instance of Point crntPnt = new Point( x, y ) varibles x and y does not belong to this particular instance. Just change the Point class as below, and make sure to change the getters and setters as well public class Point { private int x; private int y; public int getX(){ return x; } public int getY(){ return y; } public void setX(int x){ this.x = x; } public void setY(int y){ this.y = y; } } As a side note, line map.get( crntPnt.getY() - 1 ).set( crntPnt.getX(), 1 ) will throw an ArrayIndexOutOfBounds exception if the value is crntPnt.getY() is 0. So you may want to handle that too.
Java program for all walking paths of a square grid
I'm trying to write a program that outputs (in the console) all possible paths (in (x1,x1) --> (x2,x2) --> etc.. format) for navigating a grid of size NxN, from top-left to bottom-right; i.e. from (0,0) to (N-1,N-1). You can only move down or right; i.e. from (0,0) to (0,1) or to (1,0). I want the program to output each time a full path set is found (i.e. all moves from top-left to bottom-right), and what that path set is. It seems as though the best way to write this is with a recursive method inputting each move into an arrayList (see the buildPath method - the last method in the program), which is where I'm having trouble. To make it slightly more complicated, I'm also generating random grid positions that are "off-limits" and as such can't be passed through. That said, I can probably work that part out for myself once we/I figure out how to actually get the thing working with any paths at all. How would I implement a recursive method to determine which paths are possible? Any help is appreciated (even pseudo-code would be better than nothing)! Here is my code so far (the simple bits are in pseudo-code to make it easier to work through, but let me know if I should put the full code in): import java.util.*; public class RecursiveAlgorithm { public static ArrayList<Integer> allPaths = new ArrayList<Integer>(); public static ArrayList<String> pathSet = new ArrayList<String>(); public static int path; public static int N, M, x = 0, y = 0; public static String nString, mString; public static boolean grid[][]; public static int right, down; #SuppressWarnings("resource") public static void main(String[] args) { //sets the current position to (0,0) right = 0; down = 0; Input value of N (size of grid) Input value of M (number of off-limits locations) offLimits(N, M); //calls offLimits method to randomly generate off-limits locations buildPath(right, down, allPaths, N); //calls buildPath method } public static void offLimits (int N, int M) { int mCount = 0; if (M == 0){ } else { while (mCount < (M + 1)) { //int range1 = (max - min) + 1; int range1 = ((N-1) - 1) + 1; int range2 = ((N-1) - 0) + 1; int random1 = (int)((Math.random() * range1) + 1); int random2 = (int)(Math.random() * range2); //if an 'off-limits' point is generated at the finish point, move it to either 1 place to the left or 1 place above if ((random1 == N-1) && (random2 == N-1)) { int switchSelect = (int)(Math.random() * 2); while (switchSelect > 0) { switch (switchSelect){ case 1: random1--; break; case 2: random2--; break; } } } //sets a grid position to 'off-limits' (i.e. random1 = 1, random2 = 2 --> (1, 2) is 'off-limits') grid[random1][random2] = true; //counts the amount of off-limits grid locations generated mCount++; } } } public static ArrayList<String> buildPath (int right, int down, ArrayList<Integer> allPaths, int N) { //Updates path with current location (right, down) /***** FROM HERE ON IS WHERE I AM HAVING TROUBLE *****/ //Stopping Condition if ((right == N-1) && (down == N-1)) { //robot cannot go right allPaths.add(path); return pathSet; } //Recursive Steps if (right == N-1) { //robot cannot go right buildPath (right, down + 1, allPaths, N); } else if (down == N-1) { //robot cannot go down buildPath (right + 1, down, allPaths, N); } else { //robot CAN go right or go down buildPath (right + 1, down, allPaths, N); //pathSet.add(Integer.toString(right)); //pathSet.add(Integer.toString(down)); buildPath (right, down + 1, allPaths, N); if (grid[x][y] == false) { //valid new position (substitute x and y for proposed new path step) } else if (grid[x][y] == true) { //off-limits position (substitute x and y for proposed new path step) } } return pathSet; } }
You're on the right track, but headed toward a solution more complex than needed. Here's one approach that finds them allowing all 4 compass directions (not just right and down). See how simple you can make it by removing code. import java.util.LinkedHashSet; class Experimental { static class PathFinder { final int gridSize; final boolean [] [] isBlocked; final Coord goal; final LinkedHashSet<Coord> path = new LinkedHashSet<>(); final Random gen = new Random(); PathFinder(int gridSize, int nBlocked) { this.gridSize = gridSize; this.isBlocked = new boolean[gridSize][gridSize]; this.goal = new Coord(gridSize - 1, gridSize - 1); // This gets really inefficient if nBlocked is too big. for (int n = 0; n < nBlocked; ++n) { int x, y; do { x = gen.nextInt(gridSize); y = gen.nextInt(gridSize); } while (isBlocked[x][y] || (x == gridSize - 1 && y == gridSize - 1)); isBlocked[x][y] = true; } } void searchFrom(Coord coord) { if (path.contains(coord)) return; path.add(coord); if (coord.equals(goal)) System.out.println(path); if (coord.x > 0 && !isBlocked[coord.x - 1][coord.y]) searchFrom(new Coord(coord.x - 1, coord.y)); if (coord.y > 0 && !isBlocked[coord.x][coord.y - 1]) searchFrom(new Coord(coord.x, coord.y - 1)); if (coord.x < gridSize - 1 && !isBlocked[coord.x + 1][coord.y]) searchFrom(new Coord(coord.x + 1, coord.y)); if (coord.y < gridSize - 1 && !isBlocked[coord.x][coord.y + 1]) searchFrom(new Coord(coord.x, coord.y + 1)); path.remove(coord); } void printAllPaths() { searchFrom(new Coord(0, 0)); } static class Coord { final int x, y; public Coord(int x, int y) { this.x = x; this.y = y; } #Override public boolean equals(Object obj) { if (obj instanceof Coord) { Coord other = (Coord) obj; return x == other.x && y == other.y; } return false; } #Override public int hashCode() { return Integer.hashCode(x) ^ Integer.hashCode(-y); } #Override public String toString() { return '(' + Integer.toString(x) + ',' + Integer.toString(y) + ')'; } } } public static void main(String[] args) { new PathFinder(4, new boolean [] [] { { false, false, false, false }, { false, false, true, false }, { true, false, false, false }, { false, false, false, false }, }).printAllPaths(); } } One hint: The linked hash set is a reasonable choice for the path here because we need to look "backward" at each step to make sure we're not about to visit a location already visited. The set makes the lookups O(1), while the linking ensures order is maintained, which normal hash sets don't. Your problem is different.
How to compare coordinate points (of a list) in a nested for loop
Having some trouble building an equals method that compares two dimensional coordinate points in a list based on distance from point zero (0,0) -equation included. public double distanceToOrigin() { return distance(zero); } public double distance(Point that) { return Math.sqrt(Math.pow((x - that.getX()), 2) + Math.pow((y - that.getY()), 2)); } boolean equals(List<Point> lst){ boolean eq = true; for (int i=0; i<lst.size(); i++)//accounts for first element-to-compare. { for (int q = 1; q < lst.size(); q++)//accounts for second element-to-compare. { if(lst.distanceToOrigin(i) == (lst).distanceToOrigin(q))) { eq = false; } } } return eq; } I may be over-interpreting the if statement: is there a more efficient way to compare both elements (in a single line of code)? For reference: static Point zero = new Point(0, 0); public int getX(){ return x; } public int getY(){ return y; } Assistance heartily appreciated.
Examples of lists: List<Point> lst = new ArrayList<Point>(); The corrected equals method would appear similar to the following (somewhat clumsy implementation currently): boolean equals(List<Point> lst){ boolean eq = true; for (int i=0; i<lst.size(); i++)//accounts for first element-to-compare. { for (int q = 1; q < lst.size(); q++)//accounts for second element-to-compare. { if(lst.get(i).distanceToOrigin() == lst.get(q).distanceToOrigin()){ eq = false; } } } return eq; } The equals method should return boolean true or false based on whether or not element-to-compare(1) is identical to element-to-compare(2).
If you are looking for equal distances of two points you are likely better off just comparing the sum of the squares of the coordinates. That avoids comparing floats and is more efficient: class Point { public boolean isSameDistanceFromOrigin(Point other) { return x * x + y * y == other.x * other.x + other.y * other.y; } } If I'm interpreting your loop correctly you want to return false if any two points in a list are the same distance from the origin. Here's an algorithm for doing that in one line (sort of) using Java 8: public boolean areAllDifferentDistancesFromOrigin(List<Point> points) { return points.stream().noneMatch(point -> points.stream().filter(p -> p != point) .anyMatch(p-> point.isSameDistanceFromOrigin(p))); }
Depth First Search on 2-D array
I am trying to learn DFS by creating a program that navigates my ogre through a maze (2d array).This is similar to a dailyprogramming challenge, but I am doing it with just a 1x1 ogre. My maze: static int[][] maze = { {2,1,0,0,0,0,0,0,0,0}, {0,0,1,0,0,0,0,0,0,0}, {1,0,0,0,0,1,0,1,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,1,1,0,0,0,0,0,0}, {0,0,1,0,0,0,0,1,0,1}, {1,1,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,1,1,0,0,0}, {0,0,0,0,0,1,0,0,0,3}}; Where 2 is my hero (0,0), 3 is my goal (9,9), 1s are obstacles, and 0s are traverseable space. Since I am new to this, I doubt it will be needed, but ill include the whole program for easy duplication and troubleshooting. import java.awt.Point; import java.util.ArrayList; public class OgrePath { static int[][] maze = { {2,1,0,0,0,0,0,0,0,0}, {0,0,1,0,0,0,0,0,0,0}, {1,0,0,0,0,1,0,1,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,1,1,0,0,0,0,0,0}, {0,0,1,0,0,0,0,1,0,1}, {1,1,0,0,0,0,0,0,0,0}, {0,0,0,0,0,0,0,0,0,0}, {0,0,0,0,0,1,1,0,0,0}, {0,0,0,0,0,1,0,0,0,3}}; public static boolean[][] visited = new boolean[maze.length][maze[0].length]; static ArrayList<Point> neighbors = new ArrayList<Point>(); public static void main(String[] args) { OgrePath OP = new OgrePath(); for (int i=0;i<maze.length;i++){ for (int j=0;j<maze[i].length;j++){ visited[j][i] = false; } } visited[getOgre(maze).x][getOgre(maze).y] = true; System.out.println("Ogre: " + getOgre(maze)); dfs(maze, getOgre(maze)); } public static boolean dfs(int[][] maze, Point p){ neighbors = getNeighbors(maze,p); if (maze[p.x][p.y] == 3){ System.out.println("FOUND IT"); return true; } if (neighbors.isEmpty()){ return false; } for (int i=0;i<neighbors.size();i++){ System.out.println("Nieghbors: " + neighbors); System.out.println(i + "(" + p.x + "," + p.y + ")"); visited[neighbors.get(i).x][neighbors.get(i).y] = true; dfs(maze, neighbors.get(i)); } return false; } public static ArrayList<Point> getNeighbors(int[][] maze, Point p){ ArrayList<Point> neighbors = new ArrayList<Point>(); Point left = new Point(); Point right = new Point(); Point down = new Point(); Point up = new Point(); down.x = p.x - 1; down.y = p.y; if (valid(maze,down)) neighbors.add(down); up.x = p.x + 1; up.y = p.y; if (valid(maze,up)) neighbors.add(up); left.x = p.x; left.y = p.y - 1; if (valid(maze,left)) neighbors.add(left); right.x = p.x; right.y = p.y + 1; if (valid(maze,right)) neighbors.add(right); return neighbors; } public static boolean valid(int[][] maze, Point p){ if (inMaze(maze,p) && canGo(maze,p) && visited[p.x][p.y] == false) return true; else return false; } public static boolean inMaze(int[][] maze, Point p){ if (p.x < (maze[0].length - 1) && p.x > -1 && p.y < (maze.length - 1) && p.y > -1){ return true; } else return false; } public static boolean canGo(int[][] maze, Point p){ if (maze[p.x][p.y] != 1 && maze[p.x][p.y] != 4) return true; else return false; } public static Point getOgre(int[][] maze){ Point ogre = new Point(); for (int i=0;i<maze.length;i++){ for (int j=0;j<maze[i].length;j++){ if (maze[i][j] == 2){ ogre.x = j; ogre.y = i; } } } return ogre; } } I want to be able to recursively call DFS, but something about the way I wrote it makes the program stop after it has explored 1 possible line and failed.
Okay, so there a few issues I see that would prevent your code from working properly so lets look at them one at a time. First, you dfs function will not iterate through the 'for' loop because it will immediately return. Try changing dfs(maze, neighbors.get(i)); to if(dfs(maze, neighbors.get(i))){ return true; } This fixes part of your issue with only searching a single path. The second issue is with your neighbors. When your dfs does fully explore a path, it should go back a step and check all neighbors. You only have a single top-level neighbors variable, so when your branch terminates with zero neighbors, it thinks all earlier nodes have zero neighbors. Remove your static neighbors variable static ArrayList<Point> neighbors = new ArrayList<Point>(); And put a non-static version in getNeighbors ArrayList<Point> neighbors = new ArrayList<Point>(); This almost completely fixes the search, but for your maze, you will still not find the end. Your inMaze function is checking bounds incorrectly. You were checking for if x or y was less than length minus one. You only need to use 'less than' for checking the boundary. if (p.x < maze[0].length && p.x > -1 && p.y < maze.length && p.y > -1)