Java program for all walking paths of a square grid - java

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.

Related

Store the path for maze solving using Breadth First Search Algorithm

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.

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.

Determine Number of Squares a Knight Guards

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();
}

Programming test on algorithms? [closed]

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

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)

Categories

Resources