Exception in thread "main" - java

I don't know why I am incorrect in my bounds and why this error is thrown.
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException
private int gridSize = 3;
private Point currentStep = new Point(0, 0);
private Point firstStep = new Point(0, 0);
private Point lastStep = new Point(gridSize, gridSize);
private int pedometer = 0;
private int random;
private int down = 0;
private int right = 0;
private byte bottomReached = 0;
private byte rightReached = 0;
private int[][] clearPath2D;
public void createWalk2D() {
clearPath2D = new int[gridSize][gridSize];
for (currentStep = firstStep; currentStep != lastStep; pedometer++) {
step2D();
if (rightReached == 1 && bottomReached == 1) {
break;
}
}
clearField();
}
public void step2D() {
random = stepRand.nextInt();
// add a new step to the current path
currentStep.setLocation(right , down);
clearPath2D[right][down] = 4;
// calculates the next step based on random numbers and weather a side
// is being touched
if (currentStep.x == gridSize) {
rightReached = 1;
random = 1;
}
if (currentStep.y == gridSize) {
bottomReached = 1;
random = 0;
}
// decides the direction of the next step
if (random >= 0.5 && bottomReached == 0) {
down++;
} else if (random < 0.5 && rightReached == 0) {
right++;
} else if (rightReached == 1 && bottomReached == 1) {
done = true;
}
}
so I call the createWalk2D(); then I get the error and eclipse points me to this line of code:
clearPath2D[right][down] = 4;
I assume this is because I am looping incorreclty. I have not been able to find a solution and have googled for about an hour three different days.
this isn't all the code but this is the part that I think is throwing it off. Thank you in advance for any help with the error. If you need the whole code please let me know.
EDIT:
Nevermind I figured it out.
I had to add 1 to the initial declaration of the array
in this case it meant changing
clearPath2D = new int[gridSize][gridSize];
to
clearPath2D = new int[gridSize + 1][gridSize + 1];

Your immediate problem is in this section of code:
if (currentStep.x == gridSize) {
rightReached = 1;
random = 1;
}
if (currentStep.y == gridSize) {
bottomReached = 1;
random = 0;
}
You should be testing against gridSize-1, since that is the maximum valid index. As in:
if (currentStep.x == gridSize-1) {
rightReached = 1;
random = 1;
}
if (currentStep.y == gridSize-1) {
bottomReached = 1;
random = 0;
}

Related

Overflowing stack with recursion that should terminate?

I am attempting to make a random maze generator using Java and the recursive backtracking algorithm. I am getting stack overflow when I try to run this code. I know some about stack, I don't think this is infinite recursion. My guess is that I have a big logic error. Do I have to allocate more memory?
The stack trace:
Exception in thread "main" java.lang.StackOverflowError
at java.base/java.util.Vector.elementAt(Vector.java:499)
at java.base/java.util.Stack.peek(Stack.java:103)
at java.base/java.util.Stack.pop(Stack.java:84)
at mazeMaker.Maze.generateMaze(Maze.java:115)
at mazeMaker.Maze.generateMaze(Maze.java:115)
...
at mazeMaker.Maze.generateMaze(Maze.java:115)
at mazeMaker.Maze.generateMaze(Maze.java:115)
Main.java
package mazeMaker;
public class Main
{
public static void main(String[] args)
{
Maze mainMaze = new Maze(20, 30);
}
}
Maze.java
package mazeMaker;
import java.util.Random;
import java.util.Stack;
public class Maze
{
public int xSize = 0;
public int ySize = 0;
public int totalDimensions = 0;
Random randomGenerator = new Random();
public Cell[][] cellData;
public Stack<Cell> cellStack = new Stack<Cell>();
Cell tempCell; // Temporary variable used for maze generation
public Maze(int xSize, int ySize)
{
cellData = new Cell[xSize][ySize];
this.xSize = xSize;
this.ySize = ySize;
this.totalDimensions = this.xSize * this.ySize;
// Initialize array objects
for (int i = 0; i < this.xSize; i++)
{
for (int j = 0; j < this.ySize; j++)
{
cellData[i][j] = new Cell();
}
}
// Assign x and y positions
for (int i = 0; i < this.xSize; i++)
{
for (int j = 0; j < this.ySize; j++)
{
cellData[i][j].xPos = i;
cellData[i][j].yPos = j;
}
}
initBoundries();
generateMaze();
}
private void initBoundries()
{
// Initialize the border cells as visited so we don't go out of bounds
int m = this.xSize;
int n = this.ySize;
for (int i = 0; i < m; i++)
{
for (int j = 0; j < n; j++)
{
if (i == 0 || j == 0 || i == n - 1 || j == n - 1)
cellData[i][j].hasBeenVisited = true;
}
}
}
private void generateMaze(int x, int y)
{
// Set current cell as visited
cellData[x][y].hasBeenVisited = true;
// While there are unvisited neighbors
while (!cellData[x][y+1].hasBeenVisited || !cellData[x+1][y].hasBeenVisited || !cellData[x][y-1].hasBeenVisited || !cellData[x-1][y].hasBeenVisited)
{
// Select a random neighbor
while (true)
{
int r = randomGenerator.nextInt(4);
if (r == 0 && !cellData[x][y+1].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasNorthWall = false;
cellData[x][y+1].hasSouthWall = false;
generateMaze(x, y + 1);
break;
}
else if (r == 1 && !cellData[x+1][y].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasEastWall = false;
cellData[x+1][y].hasWestWall = false;
generateMaze(x+1, y);
break;
}
else if (r == 2 && !cellData[x][y-1].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasSouthWall = false;
cellData[x][y-1].hasNorthWall = false;
generateMaze(x, y-1);
break;
}
else if (r == 3 && !cellData[x-1][y].hasBeenVisited)
{
cellStack.push(cellData[x][y]);
cellData[x][y].hasWestWall = false;
cellData[x-1][y].hasEastWall = false;
generateMaze(x-1, y);
break;
}
}
}
// There are no unvisited neighbors
tempCell = cellStack.pop();
generateMaze(tempCell.xPos, tempCell.yPos);
}
// Begin generating maze at top left corner
private void generateMaze()
{
generateMaze(1,1);
}
}
Cell.java
package mazeMaker;
public class Cell
{
public boolean isCurrentCell;
public boolean hasBeenVisited;
public boolean hasNorthWall;
public boolean hasSouthWall;
public boolean hasEastWall;
public boolean hasWestWall;
public int xPos;
public int yPos;
}
The method generateMaze can never terminate not even by chance for some simple reason:
For terminating the generateMaze method would need to finish it's execution - it has to return.
There are no return statements in this method, therefore it has to pass the while loops and then continue until the execution reaches and finishes the last statement of the method.
However the last statement is generateMaze(tempCell.xPos, tempCell.yPos); which starts a new recursion, therefore your code can never ever terminate!
I tried to run your project on my own environment but unfortunately, I was not able to reproduce your issue.
However, I was facing an IndexOutOfBound exception in the method generateMaze. While I was solving this, I figured out that there was an issue in the initBoudaries method.
Indeed, when you set the boolean hasBeenVisited to true, you do not use the right variable in the IF clause. Here is the version I tried instead :
private void initBoundries()
{
// Initialize the border cells as visited so we don't go out of bounds
for (int i = 0; i < this.xSize; i++)
{
for (int j = 0; j < ySize; j++)
{
if (i == 0 || j == 0 || i == xSize - 1 || j == ySize - 1)
cellData[i][j].hasBeenVisited = true;
}
}
}
Now about the emptyStackException, I think that if this stack is empty, this means that there is no more cell to handle (as you mentioned in your comment) and the program must end. If I am right, just make sure to test if your stack is empty before call the method pop() on it like this :
// There are no unvisited neighbors
if (!cellStack.isEmpty()) {
tempCell = cellStack.pop();
generateMaze(tempCell.xPos, tempCell.yPos);
}
Hope it will help.

Java Large Number Operations Shortest Path to One

A week ago I was given a challenge from my professor to make a program that has three operations for large numbers, given as as strings. I could only pass five of the ten test cases and got an A anyway, but I still want to know what you guys would do for this problem, as far as programming techniques or an approach I didn't think of..
You are given a String representation of a number that is up to 309 digits long. You can preform three operations:
1) Add 1 to the number
2) Subtract 1
3) Divide by 2
the purpose of the program is to find the shortest path, or smallest amount of operations that can be performed on this number so that the result is 1.
ex: given "11"
1 -> 2 -> 3 -> 6 -> 12 -> 11
result: 5 steps
I had two approaches that didn't work 100%:
1: start from one or the number itself and recursively step through each possible answer until number is reached within a maximum number of steps (eg. 11, 20).
2: define all possible answers with the help of a 2-d boolean array with all possible permutaions, then step through the possible movesets one by one. this array works as a map conceptually.
Both of these approaches had limited success, wether i encountered a stackoverflow error or just ran out of memory with my large arrays. This forced me to limit the number of steps so the code could function somewhat successfully. What would be your approach?
EDIT 1:30pm
attempt 1(sorry, it has been edited severely, hence why it wasn't shown earlier...):
import java.math.BigInteger;
import java.util.Scanner;
public class Answer {
public static void main(String[] args) {
// TODO Auto-generated method stub
String str;
Scanner sc = new Scanner(System.in);
while (true) {
str = sc.nextLine();
System.out.println(answer(str));
}
// System.out.println(answer("15"));
}
private static BigInteger minNumOfJumps;
private static BigInteger big2 = BigInteger.valueOf(2);
/** smallest Number of jumps reached so far */
private static BigInteger smallestAmountOfJumps;
public static int answer(String string) {
// TODO Auto-generated method stub
BigInteger src = new BigInteger(string);
// BigInteger currentJump = BigInteger.ZERO; //used to initialize the
// nodes
// minNumOfJumps = src.divide(big2).add(BigInteger.ONE); //this must
// execute...
minNumOfJumps = new BigInteger("14"); // this must execute...
smallestAmountOfJumps = new BigInteger(minNumOfJumps.toString());
// System.out.println(minNumOfJumps);
Node n = new Node(src); // ...before this
return Integer.parseInt(getSmallestAmountOfJumps().toString());
// System.out.println(n.getSmallestAmountOfJumps().toString());
}
public static BigInteger getBig2() {
return big2;
}
public static void setBig2(BigInteger big2) {
Answer.big2 = big2;
}
public static BigInteger getMinNumOfJumps() {
return minNumOfJumps;
}
public static BigInteger getSmallestAmountOfJumps() {
return smallestAmountOfJumps;
}
public static void setSmallestAmountOfJumps(String smallestAmountOfJumps) {
Answer.smallestAmountOfJumps = new BigInteger(smallestAmountOfJumps);
}
}
/*
* I have never made a shortest path algorithm before, so i hope this is toyour
* satisfaction
*/
class Node {
/** number of nodes per creation */
private static final int NUMBER_OF_NODES_PER_NODE = 3;
/** if this number is exceeded, no more jumps are necessary. */ // SAVE THAT
// THINKING
// JUICE!
// private static BigInteger POSSIBLE_MINIMUM_NUMBER_OF_JUMPS;
private static boolean lastTransformWasRemoveOne;
private static boolean lastTransformWasAddOne;
// if one is the given value(src)
// private boolean isOneReached;
/** if the current path isn't valid */
// private boolean threadIsBroken;
// value passed during creation
private BigInteger src;
// current jump
private BigInteger currentJump;
// all possible transformations during next jump
// private Node[] path;
private Node(BigInteger src, BigInteger jump) {
currentJump = jump;
this.src = src;
// POSSIBLE_MINIMUM_NUMBER_OF_JUMPS = Answer.getMinNumOfJumps();
// this.path = new Node[NUMBER_OF_NODES_PER_NODE];
// 0 = remove | 1 = add | 2 = divide
for (int i = 0; i < NUMBER_OF_NODES_PER_NODE; i++) {
// System.out.println("i: " + i);
// System.out.println("src: " + src);
// System.out.println("compare: " +
// currentJump.compareTo(smallestAmountOfJumps));
// System.out.println("currentJump: " + currentJump);
// System.out.println("smallestAmountOfJumps: " +
// smallestAmountOfJumps);
if (src.compareTo(BigInteger.ONE) == 0) {
if (currentJump.subtract(Answer.getSmallestAmountOfJumps()).compareTo(BigInteger.ZERO) == -1) {
Answer.setSmallestAmountOfJumps(currentJump.toString());
// this below may break the code, but i think it fits with
// the logic
break;
}
} else if (i == 0) { // remove 1
// System.out.println(lastTransformWasAddOne);
// System.out.println("compare: " +
// currentJump.compareTo(smallestAmountOfJumps));
// System.out.println("currentJump: " + currentJump);
// System.out.println("smallestAmountOfJumps: " +
// smallestAmountOfJumps);
if (!lastTransformWasAddOne && currentJump.compareTo(Answer.getSmallestAmountOfJumps()) < 0) {
lastTransformWasRemoveOne = true;
Node n = new Node(transform(i), currentJump.add(BigInteger.ONE));
}
} else if (i == 1 && !lastTransformWasRemoveOne
&& currentJump.compareTo(Answer.getSmallestAmountOfJumps()) < 0) { // add
// 1
lastTransformWasAddOne = true;
Node n = new Node(transform(i), currentJump.add(BigInteger.ONE));
} else if (src.mod(Answer.getBig2()) == BigInteger.ZERO
&& currentJump.compareTo(Answer.getSmallestAmountOfJumps()) < 0) { // divide
// by
// 2
lastTransformWasRemoveOne = false;
lastTransformWasAddOne = false;
Node n = new Node(transform(i), currentJump.add(BigInteger.ONE));
} else if (currentJump.compareTo(Answer.getSmallestAmountOfJumps()) == 0)
break;
}
}
private BigInteger transform(int i) {
// TODO Auto-generated method stub
return (i == 0) ? src.subtract(BigInteger.ONE)
: (i == 1) ? src.add(BigInteger.ONE) : (i == 2) ? src.divide(Answer.getBig2()) : BigInteger.ZERO;
}
/**
* To be called once and only once.
*/
public Node(BigInteger src) {
this(src, BigInteger.ZERO);
}
}`
and this is another attempt:
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Scanner;
import java.util.Set;
public class AnswerLessProficient {
public static void main(String[] args) {
// TODO Auto-generated method stub
String str;
Scanner sc = new Scanner(System.in);
while (true) {
str = sc.nextLine();
System.out.println(answer(str));
}
// System.out.println(answer("15"));
}
private static boolean notFirstCall;
private static boolean pathIsSet;
private static boolean[][] boolArray;
private static final String ZERO = "0";
private static final BigInteger TWO = BigInteger.ONE.add(BigInteger.ONE);
private static int maximumSteps;
private static int maximumPermutations;
private static ArrayList<byte[]> listOfPaths;
private static Set<byte[]> setOfPaths;
// private static final int maximumPermutations = halfMaximumPermutations *
// 2;
// private static byte[][] path;
private static BigInteger src;
private static int steps;
private static BigInteger tempSrc;
private static byte[] tempPath;
// private static boolean followThePathsWithAlternateRoutesWasCalledOnce;
public static int answer(String s) {
// listOfPaths = new ArrayList<>();
src = new BigInteger(s);
tempSrc = new BigInteger(s);
maximumSteps = 9;
steps = maximumSteps;
maximumPermutations = (int) Math.pow(2, maximumSteps);
if (!notFirstCall) {
tempPath = new byte[maximumSteps];
setOfPaths = new HashSet<>();
int mercyVar = (int) Math.pow(2, maximumSteps);
// path = new byte[maximumPermutations][maximumSteps];
// boolArray = new boolean[maximumPermutations][maximumSteps];
for (int i = 0; i < mercyVar; i++) {
listOfPaths = new ArrayList<>();
String bin = (Integer.toBinaryString(i));
while (bin.length() < maximumSteps)
bin = (ZERO + bin);
char[] chars = bin.toString().toCharArray();
byte[] tempPath = new byte[maximumSteps];
for (int j = 0; j < maximumSteps; j++) {
// if (!pathIsSet)
// path[j] = -1;
if (chars[j] == '0') {
tempPath[j] = 2;
// path[i][j] = 2;
// boolArray[i][j] = true;
} else {
tempPath[j] = -1;
// path[i][j] = -1;
}
}
//System.out.println(Arrays.toString(tempPath));
listOfPaths.add(tempPath);
setOfPaths.add(tempPath);
findAltRoute(listOfPaths.size() - 1, maximumSteps - 1);
}
/*
* for (int i = mercyVar, j = 0; i < maximumPermutations; i++, j++)
* { for (int k = 0; k < maximumSteps; k++) { if (path[j][k] == -1)
* { path[i][k] = 1; } else { path[i][k] = 2; } } }
*/
// for (byte[] bs : setOfPaths) {
// System.out.println(Arrays.toString(bs));
// }
/*
* for (int i = maximumSteps - 1, k = 0; i >= 0 &&
* tempSrc.compareTo(BigInteger.ZERO) > 0; i--, k++) { if
* (tempSrc.compareTo(BigInteger.ONE) <= 0) if (k < steps) { steps =
* k; maximumSteps = steps; System.out.println(Arrays.toString(bs));
* break; } else break; if (bs[i] == 2 && tempSrc.mod(TWO) !=
* BigInteger.ZERO) break; tempSrc = transform(tempSrc, bs[i]); }
* tempSrc = src.add(BigInteger.ZERO);
*/
// }
// System.out.println(bin);
/*
* for (int j = 0; j < maximumSteps && i >= halfMaximumPermutations;
* j++) { // if (!pathIsSet) // path[j] = -1; if (chars[j + 1] ==
* '0') { path[i][j] = 2; // boolArray[i][j] = true; } else {
* path[i][j] = 1; } }
*/
// System.out.println(bin);
// System.out.println(Arrays.toString(path[i]));
// pathIsSet = true;
notFirstCall = true;
}
justFollowThePath();
// System.out.println(Arrays.toString(path[0]));
// System.out.println
// (Arrays.toString(path[(int) (maximumPermutations/2)-1]));
// System.out.println(Arrays.toString(path[maximumPermutations-1]));
/**
* 561-508-2204 george rubio debt forgiveness; 305-709-8255
*/
// for (int i = 0; i < maximumPermutations; i++) {
// followThePathsWithAlternateRoutes(path[i], maximumSteps - 1);
// }
// followThePathsWithAlternateRoutesWasCalledOnce = false;
/*
* for (int i = 0; i < maximumPermutations; i++) { for (int k = 0; k <
* maximumSteps; k++) {
*
* }
*
* for (int k = maximumSteps - 1; k > 0; k--) {
*
* } }
*/
// for (boolean[] bs : boolArray) {
// System.out.println(Arrays.toString(bs));
// }
// System.out.println(Arrays.toString(boolArray[maximumPermutations -
// 1]));
// System.out.println(Arrays.toString(path));
return steps;
}
private static void findAltRoute(int listIndex, int startingSearchIndex) {
if (listOfPaths.get(listIndex)[startingSearchIndex] == -1) {
// followThePathsWithAlternateRoutesWasCalledOnce = true;
// recurAlt(tempPath, maximumSteps - 1, maximumSteps - 1, (byte) 1,
// maximumSteps - 1);
for (int i = startingSearchIndex - 1; i >= 0; i--) {
if (listOfPaths.get(listIndex)[i] == 2) {
returnAltRoute(listIndex, i + 1, startingSearchIndex, (byte) 1, i);
findAltRoute(listIndex + 1, i);
return;
}
else if (i == 0) {
returnAltRoute(listIndex, i, startingSearchIndex, (byte) 1);
return;
}
}
}
for (int i = startingSearchIndex - 1; i >= 0; i--) {
if (listOfPaths.get(listIndex)[i] == -1 && listOfPaths.get(listIndex)[i + 1] == 2) {
if (i != 0) {
for (int k = i - 1; k >= 0; k--) {
if (listOfPaths.get(listIndex)[k] == 2 && listOfPaths.get(listIndex)[k + 1] == -1) {
// recurAlt(tempPath, i, k + 1, (byte) 1, k);
returnAltRoute(listIndex, k + 1, i, (byte) 1, k);
findAltRoute(listIndex, i);
}
// returnAltRoute(listIndex, 0, i, (byte)1);
// return;
}
} else {
returnAltRoute(listIndex, 0, i, (byte) 1);
return;
}
}
}
}
private static void returnAltRoute(int listIndex, int tempStart, int tempEnd, byte adjust, int returnSearchInt) {
byte[] tempPath = new byte[listOfPaths.get(listIndex).length];
for (int i = maximumSteps - 1; i >= 0; i--) {
if (i >= tempStart && i <= tempEnd) {
tempPath[i] = adjust;
} else {
tempPath[i] = listOfPaths.get(listIndex)[i];
}
}
System.out.println(Arrays.toString(tempPath));
setOfPaths.add(tempPath);
listOfPaths.add(tempPath);
maximumPermutations = setOfPaths.size();
findAltRoute(listIndex, returnSearchInt);
}
private static void returnAltRoute(int listIndex, int tempStart, int tempEnd, byte adjust) {
byte[] tempPath = new byte[listOfPaths.get(listIndex).length];
for (int i = maximumSteps - 1; i >= 0; i--) {
if (i >= tempStart && i <= tempEnd) {
tempPath[i] = adjust;
} else {
tempPath[i] = listOfPaths.get(listIndex)[i];
}
}
System.out.println(Arrays.toString(tempPath));
setOfPaths.add(tempPath);
listOfPaths.add(tempPath);
maximumPermutations = setOfPaths.size();
}
private static void justFollowThePath() {
for (byte[] bs : setOfPaths) {
//System.out.println(tempSrc.toString());
for (int i = 0; i < maximumSteps && tempSrc.compareTo(BigInteger.ZERO) > 0; i++) {
if (tempSrc.compareTo(BigInteger.ONE) == 0)
if (i < steps) {
steps = i;
maximumSteps = steps;
//System.out.println(i);
// System.out.println(Arrays.toString(tempPath));
break;
} else
break;
if (bs[i] == 2 && tempSrc.mod(TWO) != BigInteger.ZERO)
break;
tempSrc = transform(tempSrc, bs[i]);
}
tempSrc = src.add(BigInteger.ZERO);
}
}
private static void followThePathsWithAlternateRoutes(byte[] tempPath, int startingSearchIndex) {
if (tempPath[maximumSteps - 1] == -1) {
// followThePathsWithAlternateRoutesWasCalledOnce = true;
recurAlt(tempPath, maximumSteps - 1, maximumSteps - 1, (byte) 1, maximumSteps - 1);
}
for (int i = startingSearchIndex - 1; i >= 0; i--) {
if (tempPath[i] == -1 && tempPath[i + 1] == 2) {
for (int k = i - 1; k > 0; k--) {
if (tempPath[k] == 2) {
recurAlt(tempPath, i, k + 1, (byte) 1, k);
}
}
}
}
System.out.println();
for (int i = maximumSteps - 1, k = 0; i >= 0 && tempSrc.compareTo(BigInteger.ZERO) > 0; i--, k++) {
if (tempSrc.compareTo(BigInteger.ONE) <= 0)
if (k < steps) {
steps = k;
maximumSteps = steps;
System.out.println(Arrays.toString(tempPath));
break;
} else
break;
if (tempPath[i] == 2 && tempSrc.mod(TWO) != BigInteger.ZERO)
break;
tempSrc = transform(tempSrc, tempPath[i]);
}
tempSrc = src.add(BigInteger.ZERO);
}
private static BigInteger transform(BigInteger temp, byte i) {
// TODO Auto-generated method stub
return (i == -1) ? tempSrc.subtract(BigInteger.ONE)
: (i == 1) ? tempSrc.add(BigInteger.ONE) : (i == 2) ? tempSrc.divide(TWO) : null;
}
private static void recurAlt(byte[] tempPath, int tempStart, int tempEnd, byte adjust, int returnSearchInt) {
// TODO Auto-generated method stub
byte[] temp = new byte[tempPath.length];
for (int i = 0; i < temp.length; i++) {
if (i >= tempStart && i <= tempEnd)
temp[i] = adjust;
else
temp[i] = tempPath[i];
}
followThePathsWithAlternateRoutes(temp, returnSearchInt);
}
}
there are other things i've tried, but you can see where i'm going. Any pointers?
If the number is even, divide by 2. If the number is 3 mod 4, add one unless the number is actually 3. Otherwise, subtract one. Repeat until you get to 1.
Here's a proof.
First note that if the number is even, it only makes sense to divide by 2. Because if you perform some number (say 2k) of +1 or -1, then divide by 2 that's the same as dividing by two and then adding or subtracting k 1's. So by dividing by two first, you save operations.
So the only question is whether to add or subtract 1 when the number is odd. You can prove by induction that the given strategy is correct.
An odd number n is either 4x+1 or 4x+3. Note that any sequence of operations (when we're dividing by 2 whenever possible) will at some point reach either x or x+1.
We'll consider each of these in turn, and count shortest paths to x and x+1. (Checking that I've correctly identified shortest paths is omitted).
In the first case (4x+1), by subtracting one first we can get to x in 3 steps (4x+1->4x->2x->x) and x+1 in 4 steps (4x+1->4x->2x->x->x+1). By adding one first, we can get to x in 4 steps (4x+1->4x+2->2x+1->2x->x) and x+1 in 4 steps (4x+1->4x+2->2x+1->2x+2->x+1). So we might as well always subtract 1 first.
In the second case (4x+3), by subtracting one first we can get to x in 4 steps (4x+3->4x+2->2x+1->2x->x), and x+1 in 4 steps (4x+3->4x+2->2x+1->2x+2->x+1). By adding one first, we can get to x+1 in 3 steps (4x+3->4x+4->2x+2->x+1), and x in 4 steps (4x+3->4x+4->2x+2->x+1->x). So we might as well always add 1 first in this case.
In the second case, if x=0 (that is n=4*0+3=3), then our reasoning doesn't quite work, since we won't, in fact, reach x. In this case we should subtract one and divide by 2 to reach 1.
The question is labelled java, but here's some pseudocode (actually Python) to produce optimal chains:
def chain(n):
while n:
print n,
if n % 2 == 0:
n //= 2
elif n % 4 == 3 and n != 3:
n += 1
else:
n -= 1
chain(11)
My first approach will be using BFS.
There are only 2 or 3 state transition ( I assume we can't divide odd number).
But this approach only fast enough for small number.
The second approach will be using A* with smallest number as heuristic function. For example when I start with "12", I can go to:
"11", "13", "6". I will choose "6" for the next state because it closer to "1".
However this approach still not fast enough.
My third approach will be generate the answer from "1" to "100" then looking for the pattern / formula.
Edit: remove wrong formula.

How do i fix this loop in a loop in a array, Java Eclipse?

This code is for a eclipse learning class and our teacher is out can someone explain the error please and thank you. We are trying to create a loop within a loop inside an array.
package Wrok;
import java.util.Random;
public class Victory {
public static void main(String[] args) {
// TODO Auto-generated method stub
Random ran = new Random();
double x = ran.nextInt(6) + 5;
Random ran1 = new Random();
double y = ran.nextInt(6) + 5;
int Time = -1;
double[][] hello = new double [2][2];
hello[0][0]= 1;
hello[0][1]= 2;
hello[1][0]= 3;
hello[1][1]= 4;
for (int i = 0; i<Time; i++){
for (int j = 0; j<Time; j++){
if(ran = 0){
if (ran1 = 0){
System.out.println(hello[0][0]);
}
}
if(ran = 1){
if (ran1 = 0){
System.out.println(hello[1][0]);
}
}
if(ran = 0){
if (ran1 = 1){
System.out.println(hello[0][1]);
}
}
if(ran = 1){
if (ran1 = 1){
System.out.println(hello[1][1]);
}
}
}
}
}
}
The loops run from i to Time. However, i = 0 and int Time = -1 therefore the loops will never be entered as '0 < -1 yields false.
Furthermore, if(ran = 0) this is incorrect, ran is a an object from the Random class you instantiated to get random numbers. The random numbers were saved to variables x and y.

Sliding Block Solver Null Pointer Exception

I'm writing a sliding block solver that has a list of block objects (which contains block size and location of upper left corner), and a 2D array that represents the tray. Wherever there is a block, that location in the array points to the block object, otherwise it is null.
In my solver I'm generating possible moves that haven't been seen, hashing them, then choosing one to do (which changes the tray layout) and calling the solver recursively on the new tray layout. When there are no more possible move layouts that haven't been seen before I return the call, reverse the last move and continue checking the previous call, and so on until either it is solved or I run out of moves (no solution).
The problem is, I'm getting a Null Pointer Exception when I make a move. The weird thing is that it only happens after quite a few recursive calls. The program runs through several calls/moves fine, and then it seems to mess up.
generateMoves() tests if a move has been seen before by calling move(), and then reversing the move once it has checked. I think the Null Pointer is happening after it calls move(), and move() is setting toMove = layout[][]. Evidently it is looking up a position in the array that is null instead of one with the block. It seems there is a discrepancy between the list of blocks and the Tray array... Because when move() then calls setTrayAfterMove() it throws the exception. What I can't figure out is why it works for several recursive calls to solveHelper() but then breaks.
import java.io.*;
import java.util.*;
public class Solver {
Tray initial;
Tray goal;
HashSet<Integer> visited;
LinkedList<Integer> movesToSolution; // list of moves leading to solution
int recursionCounter;
boolean isSolved;
public Solver(String initial, String goal) {
this.initial = new Tray(initial);
this.goal = new Tray(this.initial, goal);
visited = new HashSet<Integer>();
movesToSolution = new LinkedList<Integer>();
recursionCounter = 0;
isSolved = false;
}
public void solve() {
if (goal.equals(initial)) {
System.out.println("Solver finished no moves");
return;
}
solveHelper(initial);
if (movesToSolution.isEmpty()) {
System.out.println("No solution");
System.exit(1);
}
printMoves();
System.out.println("Solver finished");
}
private void solveHelper(Tray t) {
Stack<Integer> possibleMoves = new Stack<Integer>();
int lastMoveMade = 0;
if (recursionCounter > 5000 || isSolved) {
return;
}
if (goal.equals(t)) {
isSolved = true;
// movesToSolution.addFirst(lastMoveMade);
return;
}
recursionCounter++;
LinkedList<Integer> movesToAdd = t.generateMoves();
Iterator<Integer> movesIter = movesToAdd.iterator();
while (movesIter.hasNext()) {
possibleMoves.push(movesIter.next());
}
while (!possibleMoves.isEmpty()) {
lastMoveMade = possibleMoves.pop();
boolean isMoved = t.move(lastMoveMade, false);
if (isMoved) {
int moveHash = t.hashCode();
visited.add(moveHash);
solveHelper(t);
}
if (isSolved) {
movesToSolution.addFirst(lastMoveMade);
return;
}
}
t.move(lastMoveMade, true);
return;
}
public void printMoves() {
for (Integer move : movesToSolution) {
System.out.println(move);
}
}
public class Tray {
private int length; // number of rows
private int width; // number of columns
private LinkedList<Block> blocks;
private Block[][] layout;
public Tray(String file) {
blocks = new LinkedList<Block>();
try {
Scanner s = new Scanner(new FileReader(file));
length = s.nextInt();
width = s.nextInt();
layout = new Block[width][length];
while (s.hasNextLine()) {
int l = s.nextInt();
int w = s.nextInt();
int r = s.nextInt();
int c = s.nextInt();
Block b = new Block(l, w, r, c);
blocks.add(b);
for (int blockX = b.col; blockX < b.col + b.width; blockX++) {
for (int blockY = b.row; blockY < b.row + b.length; blockY++) {
layout[blockX][blockY] = b;
}
}
s.nextLine();
// isOK();
}
} catch (FileNotFoundException e) {
System.out.println("File not found");
}
}
public Tray(Tray t, String file) {
blocks = new LinkedList<Block>();
try {
this.length = t.length;
this.width = t.width;
Scanner s = new Scanner(new FileReader(file));
layout = new Block[this.width][this.length];
while (s.hasNextLine()) {
int l = s.nextInt();
int w = s.nextInt();
int r = s.nextInt();
int c = s.nextInt();
Block b = new Block(l, w, r, c);
blocks.add(b);
for (int blockX = b.col; blockX < b.col + b.width; blockX++) {
for (int blockY = b.row; blockY < b.row + b.length; blockY++) {
layout[blockX][blockY] = b;
}
}
s.nextLine();
// isOK();
}
} catch (FileNotFoundException e) {
System.out.println("File not found");
}
}
public void print() {
for (Block b : blocks) {
System.out.println(b.length + " " + b.width + " " + b.col + " "
+ b.row);
}
}
public boolean equals(Object o) {
for (int x = 0; x < this.width; x++) {
for (int y = 0; y < this.length; y++) {
if (this.layout[x][y] != null
&& (((Tray) o).layout[x][y] == null || !((Tray) o).layout[x][y]
.equals(this.layout[x][y]))) {
return false;
}
}
}
return true;
}
public int hashCode() {
// TODO come up with hashcode unique to layout taking in
// consideration block at each coordinate, size of block
int hashCode = 0;
for (Block b : blocks) {
hashCode += (17 * (b.width * b.col)) + (7 * (b.length * b.row));
}
return hashCode;
}
public boolean isOK() {
Block[][] trayChecker = new Block[width][length];
Iterator<Block> blockIter = blocks.iterator();
while (blockIter.hasNext()) {
Block b = blockIter.next();
for (int x = b.col; x < x + b.width; x++) {
for (int y = b.row; y < y + b.length; y++) {
if (trayChecker[x][y] != null) {
throw new IllegalStateException(
"Two blocks cannot be in the same location");
}
if (x < 0 || x > width || y < 0 || y > length) {
throw new IllegalStateException(
"Block must be completely on the board");
}
trayChecker[x][y] = b;
}
}
}
return true;
}
// only returns possible valid moves that haven't been seen before
public LinkedList<Integer> generateMoves() {
LinkedList<Integer> movesToTry = new LinkedList<Integer>();
// TODO: generate moves that haven't been seen
int[] moveDir = { -10, 10, -1, 1 };
for (Block b : blocks) {
for (int m : moveDir) {
if (canMove(b, m)) {
int trayMove = createMove(b, m);
move(trayMove, false);
if (!visited.contains(hashCode())) {
movesToTry.add(trayMove);
}
move(trayMove, true); // reverse the move
}
}
}
return movesToTry;
}
public boolean canMove(Block b, int dir) {
int tmp = Math.abs(dir);
int y = tmp % 10;
int x = tmp / 10;
if (dir < 0) {
x = -x;
y = -y;
}
if ((b.col + x < 0 || b.col + b.width + x > this.width)
|| (b.row + y < 0 || b.row + b.length + y > this.length)) {
return false;
}
if (x == 0) {
for (int xBlock = b.col; xBlock < b.col + b.width; xBlock++) {
if (layout[xBlock][b.row + y] != null) {
return false;
}
// } else if(x > 0 && layout[xBlock][b.row + y + b.length -
// 1] != null) {
// return false;
// }
}
}
if (y == 0) {
for (int yBlock = b.row; yBlock < b.row + b.length; yBlock++) {
if (layout[b.col + x][yBlock] != null) {
return false;
}
// } else if(x > 0 && layout[b.col + x + b.width -
// 1][yBlock] != null) {
// return false;
// }
}
}
return true;
}
// only takes valid input
public boolean move(int moveDirections, boolean reverse) {
Block toMove = null;
if (moveDirections == 0) {
return false;
}
// System.out.println(moveDirections + " " + recursionCounter);
int tmp = Math.abs(moveDirections);
int moveY = tmp % 10;
tmp /= 10;
int moveX = tmp % 10;
tmp /= 10;
int blockY = tmp % 1000;
tmp /= 1000;
int blockX = tmp;
System.out.println(blockX + " + " + blockY);
if (reverse) {
if (moveDirections > 0) {
toMove = layout[blockX + moveX][blockY + moveY];
} else {
toMove = layout[blockX - moveX][blockY - moveY];
}
setTrayAfterMove(toMove, true);
if (moveDirections < 0) {
toMove.col += moveX;
toMove.row += moveY;
} else {
toMove.col -= moveX;
toMove.row -= moveY;
}
setTrayAfterMove(toMove, false);
} else {
toMove = layout[blockX][blockY];
setTrayAfterMove(toMove, true);
if (moveDirections < 0) {
toMove.col -= moveX;
toMove.row -= moveY;
} else {
toMove.col += moveX;
toMove.row += moveY;
}
setTrayAfterMove(toMove, false);
}
return true;
// 256x256
// 1x256 23x256
// 100x01 100x001 100x100
// 1x01 1x001 1x100
// 10x01 10x001 10x100
}
private int createMove(Block b, int dir) {
// multiply b.x to get 8 digits
// multiply bh .y to get 5 digits
int move = b.col * 100000;
move += (b.row * 100);
move += Math.abs(dir);
if (dir < 0) {
move *= -1;
}
return move;
}
private void setTrayAfterMove(Block b, boolean isBeforeMove) {
for (int blockX = b.col; blockX < b.col + b.width; blockX++) {
for (int blockY = b.row; blockY < b.row + b.length; blockY++) {
if(isBeforeMove) {
layout[blockX][blockY] = null;
} else {
layout[blockX][blockY] = b;
}
}
}
}
}
public class Block {
private int length;
private int width;
private int row;
private int col;
public Block(int l, int w, int r, int c) {
length = l;
width = w;
row = r;
col = c;
}
public boolean equals(Block b) {
return this.length == b.length && this.width == b.width
&& this.row == b.row && this.col == b.col;
}
}
public static void main(String[] args) {
if (args.length < 2 || args.length > 3) {
throw new IllegalArgumentException(
"Must have at least 2 and no more than 3 arguments");
}
String initialLayout = args[0];
String goalLayout = args[1];
String debug = "";
if (args.length == 3) {
if (args[0].substring(0, 2).equals("-o")) {
debug = args[0].substring(2, args[0].length());
switch (debug) {
// cases for debugging arguments go here
}
} else {
throw new IllegalArgumentException(
"First argument must start with -o");
}
initialLayout = args[1];
goalLayout = args[2];
}
Solver s = new Solver(initialLayout, goalLayout);
s.solve();
}
}
Could someone please take a look at my code? Suggestions on how to improve efficiency are also welcome. Thanks!
Instead of solving your problem, let me give you some advice on how you can root cause this yourself.
Are you developing in and IDE? If you aren't, start now.
Have you ever used a debugger? If not, start now.
Have you ever set a conditional breakpoint? If not, start now.
Set a conditional breakpoint on the variable that is null, with the condition being that the variable is null. Run your program in debug mode and see whats going on.
If the community solves this problem for you, you haven't learned anything about becoming a better programmer. Make it a point to solve this problem yourself - otherwise you are just postponing the inevitable : becoming a mediocre programmer.

How to find all connected numbers in an array?

Hey all, back again. Working on a dungeon generator and I'm actually surprising myself with the progress. Yet I still have a straggling room every now and then. I was wondering if there was a way to loop through an array and see if all the '1s' (the floor tiles) are connected, and if not, how to connect them.
Thanks!
EDIT: The array is randomly filled with rooms and corridors; here's the code:
import java.util.Random;
public class Level
{
Random random = new Random();
int[][] A = new int[100][100];
int minimum = 3;
int maximum = 7;
int xFeature = 0;
int yFeature = 0;
private void feature()
{
int i = 0;
while(i>=0)
{
xFeature = random.nextInt(100-1) + 1;
yFeature = random.nextInt(100-1) + 1;
if(A[xFeature][yFeature]==1)//||A[xFeature++][yFeature]==1||A[xFeature][yFeature--]==1||A[xFeature][yFeature++]==1)
break;
i++;
}
}
private void room()
{
int safeFall = 0;
int xCoPLUS = minimum + (int)(Math.random()*minimum);
int yCoPLUS = minimum + (int)(Math.random()*minimum);
if(yCoPLUS >= xCoPLUS)
{
for(int across = xFeature; across < xFeature+xCoPLUS+2; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS+1; vert++)
{
if(A[vert][across] == 0)
safeFall++;
else
break;
}
}
}
if(yCoPLUS < xCoPLUS)
{
for(int across = xFeature; across < xFeature+xCoPLUS+1; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS+2; vert++)
{
if(A[vert][across] == 0)
safeFall++;
else
break;
}
}
}
if((safeFall== (xCoPLUS+1) * (yCoPLUS+2)) || ((safeFall== (xCoPLUS+2) * (yCoPLUS+1))))
{
for(int across = xFeature; across < xFeature+xCoPLUS; across++)
{
for(int vert = yFeature; vert < yFeature+yCoPLUS; vert++)
{
A[vert][across] = 1;
}
}
}
}
private void corridor()
{
int xCoONE = xFeature;
int yCoONE = yFeature;
int xCoTWO = random.nextInt(10)+10;
int yCoTWO = random.nextInt(10)+10;
while(xCoONE > xCoTWO)
{
A[xCoONE][yCoONE] = 1;
xCoONE--;
}
while(xCoONE < xCoTWO)
{
A[xCoONE][yCoONE] = 1;
xCoONE++;
}
while(yCoONE > yCoTWO)
{
A[xCoONE][yCoONE] = 1;
yCoONE--;
}
while(yCoONE < yCoTWO)
{
A[xCoONE][yCoONE] = 1;
yCoONE++;
}
}
public Level()
{
firstroom();
for(int i = 0; i < 500; i++)
{
int x = random.nextInt(50);
feature();
if(x > 1)
room();
else
corridor();
}
troubleShoot();
}
So basically what happens when I create an object of this class is that a 100x100 array is filled with corridors and rooms determined by a random number. (well, a couple of them) But with how I have my room non-overlapping failsafe (safeFall in room()), I get stuck with a room that is one title out of reach every now and then.
The article Maze Generation Algorithm discusses several approaches to generating a maze. It includes links to Java examples.

Categories

Resources