Shortest path for the knight (BFS) - java

Please help me understand what I am doing wrong with my code. I am trying to get the shortest path using BFS to solve the problem but it's either giving me -1 or 2. It should give me 6 as the answer. What am I doing wrong? This is the problem:
Given a chess board, find the shortest distance(minimum number of steps) taken by a knight to reach given destination from given source.
For example, N = 8 (8 x 8 board), Source = (7, 0) Destination = (0, 7)
Minimum number of steps required is 6
My code is below:
class Point {
int x, y;
public Point(int x, int y){
this.x = x;
this.y = y;
}
}
class knightShortestPath {
int N = 8;
public static boolean visited[][];
public boolean isPositionValid(int x, int y){
if( x < 0 || y < 0 || x > this.N || y > this.N){
return false;
}
return true;
}
public void createChessBoard(int N) {
this.N = N;
visited = new boolean[this.N][this.N];
for (int i = 0; i < this.N; i++) {
for (int j = 0; j < this.N; j++) {
visited[i][j] = false;
}
}
}
public int BFS(Point source, Point destination) {
int row[] = {2, 2, -2, -2, 1, 1, -1, -1};
int col[] = {1, -1, 1, -1, 2, -2, 2, -2};
Queue<Point> queue = new LinkedList<>();
queue.offer(source);
visited[source.x][source.y] = true;
int minimumNumSteps = 0;
while (!queue.isEmpty()) {
int size = queue.size();
for (int i = 0; i < size; i++) {
Point pt = queue.poll();
if (pt.x == destination.x && pt.y == destination.y) {
return minimumNumSteps;
}
for (int j = 0; j < size; j++) {
Point next = new Point(pt.x + row[i], pt.y + col[j]);
if (isPositionValid(pt.x + row[i], pt.y + col[j]) && !visited[i][j]) {
visited[i][j] = true;
queue.offer(next);
}
}
}
minimumNumSteps++;
}
return minimumNumSteps;
}
public static void main(String[] args) {
knightShortestPath position = new knightShortestPath();
position.createChessBoard(8);
Point src = new Point(0,7);
Point dest = new Point(7,0);
System.out.println("The minimum number of steps are: " + position.BFS(src, dest)); //answer is 6
}
}

First thing: I have no idea how you can end up with a negative value. You never decrease minimumNumSteps after initializing it with 0. An overflow possibly? Seems weird to me ..
Besides that, I see two issues:
The two for loops are incorrect. You currently iterate over the queue.size(). What you want to do instead is iterating over all children of the current node.
Poll the current point outside of the for loops.
So:
while(!queue.isEmpty()) {
Point pt = queue.poll();
// check if it's target
// ...
for (int i = 0; i < row.length; i++) {
// ...
for (int j = 0; j < col.length; j++) {
// ...
}
}
}
Another note: When the queue is empty and you have not reached the goal, there is no solution. Currently, you are returning some value that may be interpreted falsely.

Related

How would I change an object's value when calling a static method from a different class?

In this practice problem, a square matrix filled with 0s and 1s is instantiated. You can flip over values (ex: 0 becomes 1 and 1 becomes 0) in a rectangle of any size, as long as the topmost corner of the rectangle is [0, 0] in the matrix. The end goal is to find how many times you must flip values over to get all the values of the matrix as 0.
If you want a longer explanation, go to http://usaco.org/index.php?page=viewproblem2&cpid=689, but that's the basic outline.
This is my code:
import java.io.*;
import java.util.*;
public class CowTip {
static int[][] mat;
public static void main( String[] args) throws IOException, InterruptedException{
Scanner scan = new Scanner(new File("cowtip.in"));
int n = scan.nextInt();
scan.nextLine();
mat = new int[n][n];
for (int x = 0; x < n; x++) {
String str = scan.nextLine();
for (int y = 0; y < n; y++) {
mat[x][y] = Integer.parseInt(str.substring(y,y+1));
}
}
Checker c = new Checker(n-1, n-1);
int count = 0;
while (true) {
c.check();
for (int x = 0; x <= c.row; x++) {
for (int y = 0; y <= c.col; y++) {
if (mat[x][y] == 0) {
mat[x][y] = 1;
}
else if (mat[x][y] == 1) {
mat[x][y] = 0;
}
}
}
count++;
c.check();
if (c.row == -1 && c.col == -1) {
break;
}
}
System.out.println(count);
}
static class Checker {
int row;
int col;
public Checker(int r, int c) {
row = r;
col = c;
}
public Checker check() {
Checker check = new Checker(-1, -1);
for (int x = mat.length-1; x >= 0; x--) {
for (int y = mat[x].length-1; y >= 0; y--) {
if (mat[x][y] == 1) {
check = new Checker(x, y);
break;
}
}
if (check.row != -1 && check.col != -1) {
break;
}
}
return check;
}
}
}
and this is the input file (named cowtip.in) :
3
001
111
111
I've excluded my current debugging code, but the problem is that the row and col values inside my check() method are the correct values, but whenever I call the check() method in my main, the values reverts back to the default and doesn't give me the correct answer, which in turn makes the loop infinite.
Any ideas on how to fix this?
EDIT: I've figured it out, but thanks guys! It was actually extremely simple (c = c.ckeck() instead of c.check()) and honestly, I was pretty frustrated considering I spent around two hours trying to debug this...
Replace c.check() with c = c.check();

StackOverflowError in Knights Tour

I have this Knight's Tour code but am getting a java.lang.StackOverflowError on line 37. I'm not really sure where to go from here to fix it. I think the code in my main has something to do with it but I'm not sure what to do with it at this point. Any help is greatly appreciated thanks.
public class Main {
public static void main(String[] args) {
Main tour = new Main();
tour.solveKnightTour();
}
private static int chessboard[][];
boolean a = true;
public Main() {
chessboard = new int[8][8];
}
private void matrixChessBoard() {
for (int i = 0; i < 8; i++) {
for (int j = 0; j < 8; j++) {
System.out.printf("%5d", chessboard[i][j]);
}
System.out.println();
}
}
static boolean tour(int advance, int horizontal, int vertical, int xMove[], int yMove[]) {
int i = 0;
int moveHoriz = 0;
int moveVert = 0;
boolean a = true;
chessboard[horizontal][vertical] = advance;
if (advance == 63) {
for (int t = 0; t < 8; t++) {
for (int u = 0; u < 8; u++) {
System.out.printf("%5d", chessboard[t][u]);
}
System.out.println("\n");
}
} else {
for (int j = 0; j < 8; j++) {
if ((horizontal + xMove[j] < 8 & (vertical + yMove[j]) >= 0 & (vertical + yMove[i]) < 8)
& (horizontal + xMove[i]) >= 0){
if (chessboard[horizontal + xMove[i]][vertical + yMove[i]] == -1){
//line 37 if (tour(moveHoriz, moveVert, advance + 1, xMove, yMove)){
break;
}
}
}
}
a = false;
chessboard[horizontal][vertical] = -1;
}
return a;
}
public boolean solveKnightTour() {
for (int x = 0; x < 8; x++) {
for (int y = 0; y < 8; y++) {
chessboard[x][y] = -1;
}
}
int xMove[] = { 2, 1, -1, -2, -2, -1, 1, 2 };
int yMove[] = { 1, 2, 2, 1, -1, -2, -2, -1 };
chessboard[0][0] = 0;
if (!tour(0, 0, 1, xMove, yMove)) {
return false;
} else {
matrixChessBoard();
}
return true;
}
}
Consider a stripped down version of your tour() method:
static boolean tour(int advance, int horizontal, int vertical, ...) {
int moveHoriz = 0;
int moveVert = 0;
if (false) {
...
} else {
if (true)
tour(moveHoriz, moveVert, advance + 1, ...);
}
}
Called with tour(0, 0, 1, ...), the function will enter with advance=0. Various assignments will be done, various tests will be made, and then the tour(moveHoriz, moveVert, advance+1, ...) statement will be executed, which evaluates to the call tour(0, 0, 1, ...). Repeat until stack overflow.
moveHoriz is passed to the advance parameter
moveVert is passed to the horizontal parameter
advance+1 is passed to the vertical parameter
This is clearly not what you intended. Since advance+1 is not passed to advance, the if (advance == 63) condition will always evaluate to false, and you never break out of the recursion.

2D Array to Rectangles

Is there a way to parse 2 dimensional array like this into a rectangle object (x,y, width, height)?. I need the array of all possible rectangles...
{0,0,0,0,0}
{0,0,0,0,0}
{0,1,1,0,0}
{0,1,1,0,0}
{0,0,0,0,0}
This would give 4 rectangles (we are looking at 0):
0,0,5,2
0,0,1,5
3,0,2,5
0,5,5,1
I have tried something like this, but it only gives the area of the biggest rectangle...
public static int[] findMaxRectangleArea(int[][] A, int m, int n) {
// m=rows & n=cols according to question
int corX =0, corY = 0;
int[] single = new int[n];
int largeX = 0, largest = 0;
for (int i = 0; i < m; i++) {
single = new int[n]; // one d array used to check line by line &
// it's size will be n
for (int k = i; k < m; k++) { // this is used for to run until i
// contains element
int a = 0;
int y = k - i + 1; // is used for row and col of the comming
// array
int shrt = 0, ii = 0, small = 0;
int mix = 0;
int findX = 0;
for (int j = 0; j < n; j++) {
single[j] = single[j] + A[k][j]; // postions element are
// added
if (single[j] == y) { // element position equals
shrt = (a == 0) ? j : shrt; // shortcut
a = a + 1;
if (a > findX) {
findX = a;
mix = shrt;
}
} else {
a = 0;
}
}
a = findX;
a = (a == y) ? a - 1 : a;
if (a * y > largeX * largest) { // here i am checking the values
// with xy
largeX = a;
largest = y;
ii = i;
small = mix;
}
}
}// end of loop
return largeX * largest;
}
this code is working with 1s, but that is not the point right now

Change order of for loops?

I have a situation where i need to loop though xyz coordinates in different orders depending on a users input. So i an area in 3D space then a set of for loops like so.
for(int x = 0; x < build.getWidth(); x++){
for(int y = 0; y < build.getHeight(); y++){
for(int z = 0; z < build.getLength(); z++){
//do stuff
}
}
}
but depending on the users input, the order may be like this.
for(int z = 0; z < build.getLenght(); z++){
for(int y = 0; y < build.getHeight(); y++){
for(int x = 0; x < build.getWidth(); x++){
//do stuff
}
}
}
or even negative.
for(int x = build.getWidth(); x > 0; x--){
for(int y = 0; y < build.getHeight(); y++){
for(int z = 0; z < build.getLength(); z++){
//do stuff
}
}
}
Is there any way to do this without hard coding every case?
Here's an n-dimensional stepper that can step in any number of dimensions in any order from any start locations to any limits. See the test code for an example.
public class Test {
public void test() {
int[] limits = {3, -5, 7};
int[] order = {0, 2, 1};
int[] starts = {0, 0, 0};
int[] steps = {1, -1, 2};
NDimensionalStepper nds = new NDimensionalStepper(limits, order, starts, steps);
do {
System.out.println(nds);
} while (nds.step());
}
public static void main(String args[]) {
new Test().test();
}
public static class NDimensionalStepper {
// The current positions in each dimension.
// Note that i[order[0]] is the fastest mover.
final int[] i;
// Starts.
final int[] starts;
// Steps.
final int[] steps;
// Limits.
final int[] limits;
// Order.
final int[] order;
// The (unordered) dimension we last stepped.
int d = 0;
// Full constructor.
public NDimensionalStepper(int[] limits, int[] order, int[] starts, int[] steps) {
// Should parameter check to ensure all are the same length.
// Should also check that each dimension will terminate.
this.i = Arrays.copyOf(starts, starts.length);
this.starts = Arrays.copyOf(starts, starts.length);
this.steps = Arrays.copyOf(steps, steps.length);
this.limits = Arrays.copyOf(limits, limits.length);
this.order = Arrays.copyOf(order, order.length);
}
// Default steps to 1.
public NDimensionalStepper(int[] limits, int[] order, int[] starts) {
this(limits, order, starts, defaultSteps(limits, starts));
}
// Default steps - 1 Towards limits.
private static int[] defaultSteps(int[] limits, int[] starts) {
int[] steps = new int[limits.length];
for (int i = 0; i < limits.length; i++) {
// Step towrds limits.
steps[i] = (int) Math.signum(limits[i] - starts[i]);
}
return steps;
}
// Default starts to 0.
public NDimensionalStepper(int[] limits, int[] order) {
this(limits, order, defaultStarts(limits.length));
}
// Default starts - 0, 0, ...
private static int[] defaultStarts(int d) {
int[] starts = new int[d];
Arrays.fill(starts, 0);
return starts;
}
// Default order to normal.
public NDimensionalStepper(int[] limits) {
this(limits, defaultOrder(limits.length));
}
// Default order - ..., 1, 0
private static int[] defaultOrder(int d) {
int[] order = new int[d];
for (int i = 0; i < d; i++) {
order[i] = d - i - 1;
}
return order;
}
// Get the current position in dimension d.
public int get(int d) {
return i[d];
}
// Take just one step. Return false if cant.
public boolean step() {
boolean stepped = false;
boolean finished = false;
while (!stepped && !finished) {
// Which dimension should be stepped (depends on order).
int o = order[d];
// Can we step in the current dimension?
while (finished(o) && d < order.length - 1) {
// Reached a limit! - Move up one dimension.
o = order[++d];
}
if (d < order.length && !finished(o)) {
// Step it.
i[o] += steps[o];
stepped = true;
// Zero all lower dimensions.
while (d > 0) {
d -= 1;
i[order[d]] = starts[order[d]];
}
} else {
// Got to the last without finding one below limit. Finished!
finished = true;
}
}
return !finished;
}
// Equal or passed the limits.
private boolean finished(int o) {
int sign = (int) Math.signum(steps[o]);
return sign * (i[o] + steps[o]) >= sign * limits[o];
}
#Override
public String toString() {
StringBuilder s = new StringBuilder();
s.append("{");
for (int d = 0; d < order.length; d++) {
s.append(get(d));
if (d < order.length - 1) {
s.append(",");
}
}
s.append("}");
return s.toString();
}
}
}
My tests of the equivalents of your three scenarios look like:
private void testBuild1(Build build) {
System.out.println("Build: x,y,z");
for (int x = 0; x < build.getWidth(); x++) {
for (int y = 0; y < build.getHeight(); y++) {
for (int z = 0; z < build.getLength(); z++) {
System.out.println("{" + x + "," + y + "," + z + "}");
}
}
}
int[] limits = {build.getWidth(), build.getHeight(), build.getLength()};
testNDS(new NDimensionalStepper(limits));
}
private void testBuild2(Build build) {
System.out.println("Build: z,y,x");
for (int z = 0; z < build.getLength(); z++) {
for (int y = 0; y < build.getHeight(); y++) {
for (int x = 0; x < build.getWidth(); x++) {
System.out.println("{" + x + "," + y + "," + z + "}");
}
}
}
int[] limits = {build.getWidth(), build.getHeight(), build.getLength()};
int[] order = {0,1,2};
testNDS(new NDimensionalStepper(limits, order));
}
private void testBuild3(Build build) {
System.out.println("Build: x--,y,z");
for (int x = build.getWidth(); x > 0; x--) {
for (int y = 0; y < build.getHeight(); y++) {
for (int z = 0; z < build.getLength(); z++) {
System.out.println("{" + x + "," + y + "," + z + "}");
}
}
}
int[] limits = {0, build.getHeight(), build.getLength()};
int[] order = {2,1,0};
int[] starts = {build.getWidth(), 0, 0};
int[] steps = {-1, 1, 1};
testNDS(new NDimensionalStepper(limits, order, starts, steps));
}
private void testNDS(NDimensionalStepper nds) {
System.out.println("--nds--");
do {
System.out.println(nds);
} while (nds.step());
}
You said depending on user input the order of loop changes. The logic for handling user input will have to be written.
You can code like this:
//Code to populate XInit, XEnd, YInit, YEnd, ZInit, ZEnd based on user input
for(int x = XInit; x < XEnd; x=XInit<XEnd?x+1:x-1){
for(int y = YInit; y < YEnd; y=YInit<YEnd?y+1:y-1){
for(int z = ZInit; z < ZEnd; z=ZInit<ZEnd?z+1:z-1){
//do stuff
}
}
}
Note: You may even want to abstract the calculation of XInit, XEnd etc. parameters in a separate method.
Your "stuff" is likely accessing the values of x, y, and z, so the way you're hard-coding is probably the easiest to follow. Your method names could clearly indicate the ordering. For the three examples you gave, it would look similar to:
public void somethingXYZ(Build build, Stuff stuff) {...}
public void somethingZYX(Build build, Stuff stuff) {...}
public void somethingXnYZ(Build build, Stuff stuff) {...}
When you're coding and want to select one of those methods, your IDE will even help you by listing the available options for that class. I think the way you're organizing it would already work well.

Using a BFS for a Maze?

I have been trying to solve this question http://dwite.ca/questions/haunted_house.html with a Breadth First Search, but I can't get all the testcases correct, and I think the problem is that, it will only count the direct shortest path to the end, and it will count any candies open, but it will not count the shortest path through the candies here is the code
import java.io.*;
import java.util.*;
public class HalloweenCandy {
static int n, candy;
static int minsteps, maxcandy;
static int totCandies=0;
public static void main(String[] args) throws FileNotFoundException {
Scanner s = new Scanner(new File("C:\\Users\\Daniel\\Desktop\\Java\\HalloweenCandy\\src\\halloweencandy\\DATA5.txt"));
while (s.hasNext()) {
n=Integer.parseInt(s.nextLine().trim());
char[][]maze=new char[n][n];
int xStart =0;
int yStart =0;
for(int y=0;y<n;++y){
String text = s.nextLine().trim();
for(int x=0;x<n;++x){
maze[x][y]=text.charAt(x);
if(maze[x][y]=='B'){
xStart=x;
yStart=y;
}
}
}
candy=0;
minsteps=0;
BFS(maze,xStart,yStart);
System.out.println(candy+" "+minsteps);
}
}
public static void BFS(char[][]maze,int xStart,int yStart){
Queue<int[]>queue=new LinkedList<int[]>();
int start[]={xStart,yStart,0,0};
queue.add(start);
while(queue.peek()!=null){
int[]array=queue.poll();
int x=array[0];int y=array[1];
if(x<0||y<0||y>n-1||x>n-1)continue;
if(maze[x][y]=='#')continue;
if(maze[x][y]=='*'){
candy++;
minsteps=array[2];
maze[x][y]='.';
}
if(maze[x][y]>='a'&&maze[x][y]<='f'){
if(candy <maze[x][y]-'a'+1)continue;
}
int[][]points = {{0,1},{1,0},{-1,0},{0,-1}};
for(int i=0;i<4;++i){
int sta[]={x+points[i][0],y+points[i][1],array[2]+1};
queue.add(sta);
}
maze[x][y]='#';
}
}
}
and here are the test cases
http://dwite.ca/home/testcase/232.html
You're on the write track, but you missed something important.
while(queue.peek()!=null){
int[]array=queue.poll();
int x=array[0];int y=array[1];
if(x<0||y<0||y>n-1||x>n-1)continue;
if(maze[x][y]=='#')continue;
if(maze[x][y]=='*'){
candy++;
minsteps=array[2];
maze[x][y]='.';
}
if(maze[x][y]>='a'&&maze[x][y]<='f'){
if(candy <maze[x][y]-'a'+1)continue;
}
int[][]points = {{0,1},{1,0},{-1,0},{0,-1}};
for(int i=0;i<4;++i){
int sta[]={x+points[i][0],y+points[i][1],array[2]+1};
queue.add(sta);
}
maze[x][y]='#'; // <== this part is wrong
}
What you're doing in that last assignment is making every square you step on into a wall. This would be the right approach if you could get through the maze without backtracking, but that's not the case. Instead, what you want to do is make sure you don't backtrack until you've picked up a new piece of candy. So, try something like this instead:
maze[x][y]='a'+candy;
That way, once you pick up a new piece of candy the square will be usable again.
However, there's still an issue here. Think about how BFS would work on this map:
3
...
*B*
...
If [0,0] is the top-left tile, then your BFS algorithm will visit the tiles in this order: [1,2], [2,1], [0,1], [1,0]. What's wrong with that? Billy is jumping between all of his neighboring squares! What you actually want him to do is restart the BFS each time he gets a new piece of candy. I'll leave it to you to figure out how to do that part.
Edit
Here's the basic algorithm you want to follow:
Begin at the start position.
Use BFS to search for the nearest piece of candy. The first piece of candy found with BFS is the nearest (or tied for nearest)!
After finding a piece of candy, you need to find the next closest piece to your current position, so treat your current position as the new start for another BFS.
I just finished solving it your way, the "greedy" way here is the code
import java.io.*;
import java.util.*;
public class HalloweenCandy {
static int n, candy;
static int minsteps, maxcandy;
static int totCandies = 0;
static boolean[][] is;
public static void main(String[] args) throws FileNotFoundException {
Scanner s = new Scanner(new File("C:\\Users\\Daniel\\Desktop\\Java\\HalloweenCandy\\src\\halloweencandy\\DATA5.txt"));
while (s.hasNext()) {
n = Integer.parseInt(s.nextLine().trim());
char[][] maze = new char[n][n];
is = new boolean[n][n];
int xStart = 0;
int yStart = 0;
for (int y = 0; y < n; ++y) {
String text = s.nextLine().trim();
for (int x = 0; x < n; ++x) {
maze[x][y] = text.charAt(x);
if (maze[x][y] == 'B') {
xStart = x;
yStart = y;
}
}
}
candy = 0;
int tot = 0;
int y = 0, x = 0;
x = xStart;
y = yStart;
for (int j = 0; j < n; ++j) {
for (int i = 0; i < n; ++i) {
is[i][j] = false;
}
}
while (true) {
char[][] grid = new char[n][n];
for (int j = 0; j < n; ++j) {
for (int i = 0; i < n; ++i) {
grid[i][j] = maze[i][j];
}
}
int lol[] = BFS(grid, x, y);
if (lol[0] == -1) {
break;
}
y = lol[2];
x = lol[1];
tot += lol[0];
}
System.out.println(candy + " " + tot);
}
}
public static int[] BFS(char[][] maze, int xStart, int yStart) {
Queue<int[]> queue = new LinkedList<int[]>();
int start[] = {xStart, yStart, 0, 0};
queue.add(start);
while (queue.peek() != null) {
int[] array = queue.poll();
int x = array[0];
int y = array[1];
if (x < 0 || y < 0 || y > n - 1 || x > n - 1) {
continue;
}
if (maze[x][y] == '#') {
continue;
}
if (maze[x][y] == '*' && !is[x][y]) {
is[x][y] = true;
candy++;
int sta[] = {array[2], x, y};
return sta;
}
if (maze[x][y] >= 'a' && maze[x][y] <= 'f') {
if (candy < maze[x][y] - 'a' + 1) {
continue;
}
}
int[][] points = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
for (int i = 0; i < 4; ++i) {
int sta[] = {x + points[i][0], y + points[i][1], array[2] + 1};
queue.add(sta);
}
maze[x][y] = '#';
}
int sta[] = {-1};
return sta;
}
}
I would like to now figure out how to solve it the dynamic way, the solution I gave only works for some cases but not all.

Categories