Related
I am using Breadth First Search Algorithm to solve a maze. My algorithm successfully finds the shortest path but it doesn't store the shortest path. It just tells me the number of steps used to complete this path but saves all the squares that have been checked no matter if they belong to the shortest path or not. I really tried quite a few ways to store the shortest path but I'm getting errors with the path where squares that are not in the shortest path are also included. If you could find me a way to store the shortest path in an ArrayList or ArrayQueue or array or anything. The correctPath() is what i did so i can decide which squares are in the shortest path but it's wrong. I dont think that is so complicated just i cannot figure out how to do it. Thanks for your time.
Squares have as attributes a x and y position and also the distance from the destination.
public class BreathAlgorithm {
// Java program to find the shortest path between a given source cell to a destination cell.
static int ROW;
static int COL;
// These arrays are used to get row and column numbers of 4 neighbours of a given cell
static int[] rowNum = {-1, 0, 0, 1};
static int[] colNum = {0, -1, 1, 0};
// check whether given cell (row, col) is a valid cell or not.
static boolean isValid(int row, int col)
{
// return true if row number and column number is in range
return (row > 0) && (row <= ROW) && (col > 0) && (col <= COL);
}
// Checks if a square is an adjacent to another square
static boolean isNearSquare(Square a,Square b){
int x = 1;
int y = 0;
if((Math.abs((a.getX()+x) - (b.getX()+x))) + (Math.abs((a.getY()+y) - (b.getY()+y))) != 1){
return false;
}
x = -1;
y = 0;
if((Math.abs((a.getX()+x) - (b.getX()+x))) + (Math.abs((a.getY()+y) - (b.getY()+y))) != 1){
return false;
}
x = 0;
y = 1;
if((Math.abs((a.getX()+x) - (b.getX()+x))) + (Math.abs((a.getY()+y) - (b.getY()+y))) != 1){
return false;
}
x = 0;
y = -1;
return (Math.abs((a.getX() + x) - (b.getX() + x))) + (Math.abs((a.getY() + y) - (b.getY() + y))) == 1;
}
// returns the Square of the ending position
public static Square findEnd(int[][] mat){
for (int i=0;i<mat.length;i++){
for(int j=0;j<mat[0].length;j++){
if(mat[i][j] == 9)
return new Square(i,j,0);
}
}
return new Square(1,1,0);
}
/*
In this method i tried to define which squares are to be deleted from the fullPath
and return a new path with only the squares who are actually used in the shortest path.
This method doesn't work for all examples it just works for some so i guess it is lacking.
*/
public static ArrayQueue<Square> correctPath(ArrayList<Square> path) throws QueueFullException {
int i=0;
while(i<path.size()-1){
if (path.get(i).getDistance() == path.get(i+1).getDistance()){
if (path.get(i+2)!=null && path.get(i-1)!=null && (!isNearSquare(path.get(i),path.get(i+2)) || !isNearSquare(path.get(i),path.get(i+2)))){
path.remove(i);
}
else if (path.get(i+2)!=null && path.get(i-1)!=null && (!isNearSquare(path.get(i+1),path.get(i-1)) || !isNearSquare(path.get(i+1),path.get(i+2)))){
path.remove(i+1);
}
else if (!isNearSquare(path.get(i),path.get(i+1))){
path.remove(i);
}
}
i++;
}
ArrayQueue<Square> correctPath = new ArrayQueue<>(path.size());
while(i>=0){
correctPath.enqueue(path.get(i));
i--;
}
return correctPath;
}
static void printCorrectPath(ArrayQueue<Square> correctPath) throws QueueEmptyException {
Square[] originalPath = new Square[correctPath.size()];
for(int i=originalPath.length-1;i>=0;i--){
originalPath[i] = correctPath.dequeue();
}
int i=0;
while(i<originalPath.length-1){
if(i == 0) System.out.println(originalPath[i]+" is the starting point.");
System.out.println("From "+originalPath[i]+"to "+originalPath[i+1]);
i++;
if(i == originalPath.length-1) System.out.println(originalPath[i]+" is the ending point.");
}
}
public static void searchPath(int[][] mat,Square start) throws QueueEmptyException, QueueFullException {
//mat is the maze where 1 represents a wall,0 represent a valid square and 9 is the destination
// When a square is visited from 0 it becomes a 2
ROW=mat.length;
COL=mat[0].length;
Square dest = findEnd(mat); // search for the number 9 and make a new Square and put it in dest
int dist = BFS(mat, start, dest); // find the least distance
if (dist != Integer.MAX_VALUE)
System.out.println("\nShortest Path is " + dist+" steps.");
else
System.out.println("Shortest Path doesn't exist");
}
// function to find the shortest path between a given source cell to a destination cell.
static int BFS(int[][] mat, Square src, Square dest) throws QueueFullException, QueueEmptyException {
ArrayList<Square> fullPath = new ArrayList<>(); // path of all the squares checked
boolean [][]visited = new boolean[ROW][COL]; // if a square is visited then visited[x][y] = true
ArrayQueue<Square> q = new ArrayQueue<>(mat.length*mat[0].length); // Create a queue for BFS
// check source and destination cell of the matrix have value 1
if (mat[src.getY()][src.getX()] != 0 || mat[dest.getX()][dest.getY()] != 9) {
return -1;
}
mat[src.getY()][src.getX()] = 2; // Mark the source cell as visited
visited[src.getX()][src.getY()] = true;
q.enqueue(src); // Enqueue source cell
fullPath.add(src); // Add source to the full path
while (!q.isEmpty()) // Do a BFS starting from source cell
{
Square curr = q.front();
if (curr.getX() == dest.getX() && curr.getY() == dest.getY()) { // If we have reached the destination cell we are done
printCorrectPath(correctPath(fullPath));
return curr.getDistance();
}
q.dequeue(); // Otherwise dequeue the front cell in the queue and enqueue its adjacent cells
for (int i = 0; i < 4; i++){
int row = curr.getX() + rowNum[i];
int col = curr.getY() + colNum[i];
// if adjacent cell is valid, has path and not visited yet, enqueue it.
if (isValid(row, col) && mat[row][col] == 0 || mat[row][col] == 9 && !visited[row][col]){
mat[row][col] = 2;
visited[row][col] = true; // mark cell as visited and enqueue it
Square Adjcell = new Square(row,col, curr.getDistance() + 1 );
q.enqueue(Adjcell);
fullPath.add(Adjcell);
}
}
}
return -1; // Return -1 if destination cannot be reached
}
}
Here is the class where i do the testings.
public class MazeRunner {
// Maze is a 2d array and it has to be filled with walls peripherally
// with walls so this algorithm can work. Our starting position in this
// will be (1,1) and our destination will be flagged with a 9 which in
// this occasion is (11,8).
private int[][] maze ;
private final List<Integer> path = new ArrayList<>();
public long startTime,stopTime;
public MazeRunner(int [][] maze){
this.maze = maze;
}
public void runBFSAlgorithm(int startingX,int startingY) throws QueueEmptyException, QueueFullException {
startTime = System.nanoTime();
BreathAlgorithm.searchPath(maze,new Square(startingX,startingY,0));
stopTime = System.nanoTime();
System.out.printf("Time for Breath First Algorithm: %.5f milliseconds.\n",(stopTime-startTime)*10e-6);
}
public void printMaze(){
for (int[] ints : maze) {
for (int anInt : ints) {
System.out.print(anInt + " ");
}
System.out.println();
}
}
public static void main(String[] args) throws FileNotFoundException, QueueEmptyException, QueueFullException {
int [][] maze = {{1,1,1,1,1,1,1,1,1,1,1,1,1},
{1,0,1,0,1,0,1,0,0,0,0,0,1},
{1,0,1,0,0,0,1,0,1,1,1,0,1},
{1,0,0,0,1,1,1,0,0,0,0,0,1},
{1,0,1,0,0,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,0,0,1},
{1,0,1,0,1,0,0,0,1,1,1,0,1},
{1,0,1,0,1,1,1,0,1,0,1,0,1},
{1,0,0,0,0,0,0,0,0,0,1,9,1},
{1,1,1,1,1,1,1,1,1,1,1,1,1}};
int[] startingPoint = {1,1};
MazeRunner p = new MazeRunner(maze);
p.printMaze();
p.runBFSAlgorithm(startingPoint[0],startingPoint[1]);
}
}
My execution would look like this:
The execution output
Give an instance of Square an extra property: Square cameFrom;.
Then in your BFS change:
q.enqueue(Adjcell);
to:
Adjcell.cameFrom = curr;
q.enqueue(Adjcell);
Then, change correctPath so it takes dest as argument and builds the path as an ArrayList<Square> from following the linked list formed by the cameFrom property.
This list will then just need to be reversed to get it in the right order.
javascript code in processing 3.5.3 not working, not sure why. It's supposed to create circles and have them bounce around the screen, instead it makes the right amount of circles but they don't move. It seems like intlist.set() isn't working, but I'm not sure why. Help would be appreciated.
import javax.swing.JOptionPane;
int x = 200;
int y = 150;
int b = 50;
float slope = -1;
int numOfCircles = 10;
IntList initPosX = new IntList();
IntList initPosY = new IntList();
IntList exes = new IntList();
IntList whys = new IntList();
IntList xSpeeds = new IntList();
IntList ySpeeds = new IntList();
void setup()
{
numOfCircles = int(JOptionPane.showInputDialog(frame, "How many circles ya want?"));
size(800,400);
for(int i = 0; i < numOfCircles; i++)
{
int toAddX = int(random(0,400));
initPosX.append(toAddX);
int toAddY = int(random(0,300));
initPosY.append(toAddY);
exes.append(0);//(int(random(-30,30)));
whys.append(0);//(int(random(-30,30)));
xSpeeds.append(1);
ySpeeds.append(1);
}
}
void draw()
{
background(100,100,100,255);
for(int i = 0; i < numOfCircles; i++)
{
ellipse(exes.get(i) + initPosX.get(i), whys.get(i) + initPosY.get(i), 20, 20);
exes.set(i, i + xSpeeds.get(i));
whys.set(i, i + ySpeeds.get(i));
if(exes.get(i) > width || exes.get(i) <= 0)
{
print("side wall hit");
xSpeeds.set(i, i*= slope);
}
if(whys.get(i) > height || whys.get(i) <= 0)
{
print("roof hit");
ySpeeds.set(i, i*= slope);
}
}
}
The problem is at those lines:
exes.set(i, i + xSpeeds.get(i));
whys.set(i, i + ySpeeds.get(i));
What you want to do there, is add the speed to the current value of exes/whys at the index i.
But what you are actually doing is set them to the index + the speed.
Since the index is never going to change, neither are the positions.
To fix this, replace it with this:
exes.set(i, exes.get(i) + xSpeeds.get(i));
whys.set(i, whys.get(i) + ySpeeds.get(i));
Update
When changing just this, your code still won't work properly, because the collision detection:
if(exes.get(i) > width || exes.get(i) <= 0)
{
print("side wall hit");
xSpeeds.set(i, i*= slope);
}
if(whys.get(i) > height || whys.get(i) <= 0)
{
print("roof hit");
ySpeeds.set(i, i*= slope);
}
does not detect collision for the actual position, because that would be the position (exes, whys) + the initPos's, so it should be
if (exes.get(i) + initPosX.get(i) > width || exes.get(i) + initPosX.get(i) <= 0)
{
//the code
}
if (whys.get(i) + initPosY.get(i) > height || whys.get(i) + initPosY.get(i) <= 0)
{
//the code
}
If you were to start it now however, you would get an error. That is because you changing to something negative. instead of i*= slope just use int(i * slope) (because int * float returns a float, you have to convert the result to an int by using int()).
Furthermore, you again don't actually want the index, but the current value at the index:
xSpeeds.set(i, int(xSpeeds.get(i) * slope); //the same for ySpeeds
I am having a bit of trouble producing the right output for this assignment and not sure what I am doing wrong.
There are K knights on N x N chessboard and you are to determine how many squares they are guarding. A square is guarded if it is either occupied by a
knight or is reachable by a knight by a single move.
Write a program that reads positive integers N and K and then K positions of knights, and prints the
number of squares that are guarded by these K knights.
Example of input: 8 2 c 1 e 2
Corresponding output: 10
Example of input: 8 6 c 1 e 2 d 4 c 7 f 7 h 6
Corresponding output: 30
When I input the first example it works, but when I input the second example it gives me 34
package knightguard;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class KnightGuard {
static class Position {
int x;
int y;
public Position(int x, int y) {
this.x = x;
this.y = y;
}
public boolean equals(Position p) {
if (p.x == x && p.y == y) {
return true;
}
return false;
}
#Override
public String toString() {
return x + "," + y;
}
}
ArrayList<Position> knightPositions;
int size;
int no_of_knights;
public KnightGuard(int size, int k, ArrayList<Position> knightPositions) {
this.knightPositions = knightPositions;
no_of_knights = k;
this.size = size;
}
public int getSafePositions() {
Set<Position> safePos = new HashSet<>();
for (Position p : knightPositions) {
if (isValid(p.x - 2, p.y - 1)) {
safePos.add(new Position(p.x - 2, p.y - 1));
}
if (isValid(p.x - 2, p.y + 1)) {
safePos.add(new Position(p.x - 2, p.y + 1));
}
if (isValid(p.x + 2, p.y - 1)) {
safePos.add(new Position(p.x + 2, p.y - 1));
}
if (isValid(p.x + 2, p.y + 1)) {
safePos.add(new Position(p.x + 2, p.y + 1));
}
if (isValid(p.x - 1, p.y - 2)) {
safePos.add(new Position(p.x - 1, p.y - 2));
}
if (isValid(p.x - 1, p.y + 2)) {
safePos.add(new Position(p.x - 1, p.y + 2));
}
if (isValid(p.x + 1, p.y - 2)) {
safePos.add(new Position(p.x + 1, p.y - 2));
}
if (isValid(p.x + 1, p.y + 2)) {
safePos.add(new Position(p.x + 1, p.y + 2));
}
}
return safePos.size();
}
private boolean isValid(int x, int y) {
if (x < 0 || x >= size || y < 0 || y >= size) {
return false;
}
if (knightPositions.contains(new Position(x, y))) {
return false;
}
return true;
}
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int size = s.nextInt();
int knights = s.nextInt();
ArrayList<Position> knightPos = new ArrayList<>();
for (int i = 0; i < knights; i++) {
int x = s.next().charAt(0) - 'a';
int y = s.nextInt() - 1;
knightPos.add(new Position(x, y));
}
KnightGuard knightGuard = new KnightGuard(size, knights, knightPos);
System.out.println(knightGuard.getSafePositions());
s.close();
}
}
One issue in using this approach is that possible duplicate positions may be generated for different knights. Example; using the picture in the post, the two knights at positions D4 and H6 can BOTH move to the square at F5. Therefore, the posted code will count this position TWICE. In theory, there could possibly be eight (8) knights at eight different positions and all could move to the same square. A check is going to have to be made to eliminate these possible “duplicate’ positions.
I am a little confused by the KnightGuard class and the getSafePositions method. The KnightGuard class has a list of positions, this is the list of the positions of the given knights. However the getSafePositions method simply returns the number of different moves all the knights could move from their respective positions. This method does not take into account that the previous knight could also move to the same position as described in the first paragraph.
To simplify things… I feel a class called Knight would be a better approach. A Knight would have a Position variable to indicate where “THIS” knight is positioned on the board. In Addition, the Knight class would contain an ArrayList of Position objects to indicate all the possible moves this knight can make given its position. A Knight should NOT be aware of any other Knights and the list of positions it can move to are all the positions it could move to regardless if there is another piece at that position. This list would contain a minimum of two (2) positions and up to a maximum of eight (8) different positions.
When a new Knight object is created, the list of possible moves is automatically generated upon instantiation along with its own position on the board, which we will need later.
Below is an example of this Knight class. It should be noted that in this class and in the main method, I changed the indexing of the board to start at 1 (a) not zero (0) on the left and moves right and also on the y index where the bottom y index is 1 and moves up. In addition a SetValidMoves method is created to allow the list of positions this knight can move, to be changed. This may be needed if another knight occupies one of the positions in this knight's list of guarded positions. This code is not taking advantage of this since we are only interested in the number of guarded squares.
public class Knight {
Position knightPosition;
ArrayList<Position> validMoves;
int boardSize;
public Knight(Position position, int inBoardSize) {
knightPosition = position;
validMoves = new ArrayList<Position>();
boardSize = inBoardSize;
SetValidMoves();
}
public Position GetKnightPosition() {
return knightPosition;
}
public ArrayList<Position> GetValidMoves() {
return validMoves;
}
public void SetValidMoves(ArrayList<Position> newMoves) {
validMoves = newMoves;
}
private void SetValidMoves() {
int thisX = knightPosition.x;
int thisY = knightPosition.y;
// check for bottom moves 2 down 1 left - right
if (thisY - 2 >= 1) {
if (thisX + 1 <= boardSize) {
validMoves.add(new Position(thisX + 1, thisY - 2));
}
if (thisX - 1 >= 1) {
validMoves.add(new Position(thisX - 1, thisY - 2));
}
}
// check for bottom moves 1 down 2 left - right
if (thisY - 1 >= 1) {
if (thisX + 2 <= boardSize) {
validMoves.add(new Position(thisX + 2, thisY - 1));
}
if (thisX - 2 >= 1) {
validMoves.add(new Position(thisX - 2, thisY - 1));
}
}
// check for top moves 2 up 1 left - right
if (thisY + 2 <= boardSize) {
if (thisX + 1 <= boardSize) {
validMoves.add(new Position(thisX + 1, thisY + 2));
}
if (thisX - 1 >= 1) {
validMoves.add(new Position(thisX - 1, thisY + 2));
}
}
// check for top moves 1 up 2 left - right
if (thisY + 1 <= boardSize) {
if (thisX + 2 <= boardSize) {
validMoves.add(new Position(thisX + 2, thisY + 1));
}
if (thisX - 2 >= 1) {
validMoves.add(new Position(thisX - 2, thisY + 1));
}
}
}
}
With an ArrayList of Knight objects (knightsOnBoard) it is possible to loop thought this list and create an ArrayList of Position objects (validMoves) where each Position indicates a position one or more of the knights is guarding. Since duplicates are not wanted, we simply ignore positions that are already in the validMoves list.
knightsOnBoard is the global list of Knight objects
private static ArrayList<Position> GetAllDifferentPositions() {
ArrayList<Position> validMoves = new ArrayList<Position>();
for (Knight curKnight : knightsOnBoard) {
for (Position curPos : curKnight.validMoves) {
if (!validMoves.contains(curPos)) {
validMoves.add(curPos);
}
}
}
return validMoves;
}
Since the above code uses the contains property to check if the position is already in the list validMoves, a change is needed in the Position class to publicly expose the equals method using an Object parameter.
#Override
public boolean equals(Object obj) {
if (obj instanceof Position) {
Position other = (Position)obj;
if (this.x == other.x && this.y == other.y)
return true;
}
return false;
}
Now we have an ArrayList of Position objects that do not have duplicates. Unfortunately, there is one last hurdle to clear. There needs to be a check to see if a Knight can move to a square but it is already occupied by another knight. Therefore we will need to remove all the ‘Knight`’s positions in the list of positions the knights can move to.
The reason this must be done is that we need to add all the given Knight’s positions to the count since the square the knight is sitting on is also a “guarded” square. Since it is possible this position is already in the list… we need to remove them. In other words, we know a Knight will not have “its” own position in its list of moves, however it may have another Knights position in its list of moves.
private static void RemoveAllKnightPositions(ArrayList<Position> allPositions) {
for (Knight curKnight : knightsOnBoard) {
if (allPositions.contains(curKnight.knightPosition)) {
allPositions.remove(curKnight.knightPosition);
}
}
}
Now the list of positions (finalResults below) has no duplicates and in addition, we know the list does not contain any of the positions where a knight is sitting. Therefore, the number of guarded squares would be the number of positions in the positions list finalResults PLUS the number of knights.
Finally, putting this all together in the main method below. Please note the code changes the indexing order so BOTH x and y start at one (1) and end at boardSize. I hope this makes sense and helps.
static ArrayList<Knight> knightsOnBoard = new ArrayList<Knight>();
public static void main(String[] args) {
Scanner s = new Scanner(System.in);
int boardSize = s.nextInt();
int knights = s.nextInt();
for (int i = 0; i < knights; i++) {
int x = (s.next().charAt(0) - 'a') + 1;
int y = s.nextInt();
Knight newKnight = new Knight(new Position(x,y), boardSize);
knightsOnBoard.add(newKnight);
System.out.println("Knight at : " + newKnight.knightPosition.x + " " + newKnight.knightPosition.y);
}
ArrayList<Position> finalResults = GetAllDifferentPositions();
RemoveAllKnightPositions(finalResults);
System.out.println("Positions: " + (finalResults.size() + knightsOnBoard.size()));
s.close();
}
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.
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