Java getting stuck in while loop - java

So I have created this program to randomly place objects in a room with a number of constraints. One such constraint is that every object has to be at least dis distance away from every other object already placed in the room. My entire code works well, however I often have to problem that the code stays stuck in the while loop. Here is that part of the code:
// distance vector to check whether the distance is kept
double[] dis2 = new double[k+1];
// distance vector to check whether the distance to the input/output is kept
double[] dis4 = new double[2];
dis4[0] = Math.abs(NewObjectX - inputX) + Math.abs(NewObjectY - inputY);
dis4[1] = Math.abs(NewObjectX - outputX) + Math.abs(NewObjectY - outputY);
// Check the distance constraints
int l = 0;
while (l<k+1) {
dis2[l] = Math.abs(NewObjectX - PlacedX[l]) + Math.abs(NewObjectY - PlacedY[l]);
if (dis2[l]<dis || dis3>2.5*dis || dis4[0]<dis || dis4[1]<dis) {
NewObjectX = Math.random()*(dim[1]-dim[0]) + dim[0]*0.5;
NewObjectY = Math.random()*(dim[3]-dim[2]) + dim[2]*0.5;
dis3 = Math.abs(NewObjectX - PlacedX[k]) + Math.abs(NewObjectY - PlacedY[k]);
dis4[0] = Math.abs(NewObjectX - inputX) + Math.abs(NewObjectY - inputY);
dis4[1] = Math.abs(NewObjectX - outputX) + Math.abs(NewObjectY - outputY);
l=0;
} else {
l++;
}
}
What happens: I randomly place a machine in the room and then I check the distance constraints with every already placed object in the while loop:
In the while loop, I check the distance constraint with the first, then second and so on objects that have already been placed.
If the distance constraints are not met, then a new randomly selected spot is selected and I restart the while loop l=0
I am not sure why my code sometimes stays stuck in that loop and most of the time works perfectly.
Could someone help me? Did I make an error?
Thank you so much :)
Sam
EDIT:
Here is a copy of the simplified code with only 1 constraint instead of 4 in the while loop:
public static double[][] initialPop(double[] dim, double dis, int WSNr, double[] ioPlace) {
int[] WStoPlace = new int[WSNr-2];
for (int i=1; i<WSNr-1; i++) {
WStoPlace[i-1] = (i);
}
double[][] placed = new double[WSNr-2][3];
double ObjectX;
double ObjectY;
// now place the first object
ObjectX = dim[1]/2;
ObjectY = dim[3]/2;
placed[0][0] = WStoPlace[0];
placed[0][1] = ObjectX ;
placed[0][2] = ObjectY;
for (int i=1; i<WSNr-2; i++) {
//place the ith object
ObjectX = Math.random()*(dim[1]-dim[0]) + dim[0]*0.5;
ObjectY = Math.random()*(dim[3]-dim[2]) + dim[2]*0.5;
int l=0;
while (l<i) {
double dis2 = Math.abs(ObjectX - placed[l][1]) + Math.abs(ObjectY - placed[l][2]);
if (dis2<dis) {
ObjectX = Math.random()*(dim[1]-dim[0]) + dim[0]*0.5;
ObjectX = Math.random()*(dim[3]-dim[2]) + dim[2]*0.5;
l=0;
} else {
l++;
}
}
// Add the newly placed object
placed[i][0] = WStoPlace[i];
placed[i][1] = ObjectX;
placed[i][2] = ObjectY;
}
return placed;
}
This code is then called by my main program in a for-loop:
public static void main(String[] args) {
// define all the variables ...
int popFlow = 5;
double[] dim = new double [4];
dim[0] = 3; // length of WS (x)
dim[2] = 3; // width of WS (y)
dim[1] = 100; // length of facility (x)
dim[3] = 40;
double dis = 8;
int WSNr = 22;
double[] ioPlace = new double[4];
ioPlace[0] = 0; // int xi = 0;
ioPlace[1] = 5; // int yi = 2;
ioPlace[2] = 100; // int xo = 50;
ioPlace[3] = 35;
double[][] TotalPop = new double[popFlow][2*WSNr];
// Flow-related placed Workstations
for (int i=0; i<popFlow; i++) {
double [][] Pos = initialPop(dim, dis, WSNr, ioPlace);
for (int j=0; j<WSNr-2; j++) {
int Value = (int) Pos[j][0];
TotalPop[i][Value] = Pos[j][1];
TotalPop[i][Value+WSNr] = Pos[j][2];
}
}
}

As mentioned in the question's comments, you need to limit the loop. As a quick solution, you can have a counter that limits the while loop functionality and reset the entire logic which its probability to NOT go into same situation again is high. But that really should be handled better and check in which case exactly the loop would not end.
If the reason found and could be handled by the breaking conditions then it would be better as it would be more definite solution. Nevertheless, limiting the iteration for emergency is almost a must have. Here is simple sample on your code that would do something similar
public static double[][] initialPop(double[] dim, double dis, int WSNr, double[] ioPlace) {
boolean reset = false;
double[][] placed = null;
while (!reset) {
int[] WStoPlace = new int[WSNr - 2];
for (int i = 1; i < WSNr - 1; i++) {
WStoPlace[i - 1] = (i);
}
placed = new double[WSNr - 2][3];
double ObjectX;
double ObjectY;
// now place the first object
ObjectX = dim[1] / 2;
ObjectY = dim[3] / 2;
placed[0][0] = WStoPlace[0];
placed[0][1] = ObjectX;
placed[0][2] = ObjectY;
for (int i = 1; i < WSNr - 2; i++) {
//place the ith object
ObjectX = Math.random() * (dim[1] - dim[0]) + dim[0] * 0.5;
ObjectY = Math.random() * (dim[3] - dim[2]) + dim[2] * 0.5;
// Problem is the while, not the for so we define the limit here
int limit = 100;
int counter = 0;
// Make sure it's false as it might be changed in some iteration before!
// I promised, check the comments below !
reset = false;
int l = 0;
while (l < i) {
double dis2 = Math.abs(ObjectX - placed[l][1]) + Math.abs(ObjectY - placed[l][2]);
if (dis2 < dis) {
ObjectX = Math.random() * (dim[1] - dim[0]) + dim[0] * 0.5;
ObjectX = Math.random() * (dim[3] - dim[2]) + dim[2] * 0.5;
l = 0;
} else {
l++;
}
if (counter >= limit) { // Now that's enough !
reset = true;
break;
}
counter++;
}
if (reset) { // I said it's enough, I want full reset so ...
reset = false; // going to break to the while-loop that checking this, and we want to enter again !
break;
} else {
// Not sure at this point this will be the last execution
// So just make it true, so we do not enter the entire logic again
// after finally settling to our result !!!!
// If it's not the last execution which means we are entering another for-loop iteration then
// we will reset this to false, i promise !
reset = true;
// Add the newly placed object
placed[i][0] = WStoPlace[i];
placed[i][1] = ObjectX;
placed[i][2] = ObjectY;
}
}
}
return placed;
}

You need a breakout. Add a counter or timer or check off coords as you try them until they are all checked. The way it is now there is no way to end the loop if your conditions in the "if" statement are always meet, it will just keep setting 'l' to 0 and your while loop just keeps looping.

Related

Method to find if a snake in a snake game has made a loop

I am relatively new to java, and I have an idea for a mechanic I want to implement in to my game. However, I have no idea how to go about solving this problem. My snake game works on a basic coordinate system. I want it to be so that when the snake makes a closed loop (a rectangle or square) the game will detect it has made a loop. I have tried writing a method to locate the part of the snake's body that is the most upper-left, and then checking from there, but it seems to not work very well. Here is the method I attempted to write, if It helps at all. Thank you for any help!!
public boolean checkRing()
{
int topLeftX = 5000;
int topLeftY = 5000;
for(int i = bodyParts;i>0;i--)
{
// Finds coordinates of top left box
if(x[i] < topLeftX)
{
topLeftX = x[i];
}
if(y[i] < topLeftY)
{
topLeftY = y[i];
}
}
// Use isBody() method below (not bug tested) to check for rectangle
boolean lineFoundVert = false;
int checkingX = topLeftX;
int checkingY = topLeftY;
int vertCounter = 1;
while(!lineFoundVert)
{
if(isBody(checkingX, checkingY))
{
vertCounter++;
checkingX++;
}
else
lineFoundVert = true;
}
boolean lineFoundHori = false;
checkingX = topLeftX;
checkingY = topLeftY;
int horiCounter = 1;
while(!lineFoundHori)
{
if(isBody(checkingX, checkingY))
{
horiCounter++;
checkingY++;
}
else
lineFoundHori = true;
}
debug1X = topLeftX + 1;
debug1Y = topLeftY + vertCounter;
debug2X = topLeftX + horiCounter;
debug2Y = topLeftY + 1;
if(isBody(topLeftX + 1, topLeftY + vertCounter) && isBody(topLeftX + horiCounter, topLeftY + 1))
{
return true;
}
return false;
}```
Here is an approximate solution:
private boolean isEdgeCoordinate(Coordinate[] bodyparts, int index) {
// for every bodypart check that its neighbours (bodypart one before and
// bodypart one after) dont share X axis and dont share Y axis. As long
// as that is the case it is an edge.
//additionally for the last bodypart you needto check that it has first
// bodypart as a neighbour and check them as neighbours otherwise no
// rectangle to begin with
}
using this method check the amount of edges in your bodyparts array. If the total number of edges == 4 you have got a square/rectangle

Why is this java application hang/freezing?

I am currently writing a code that calculates PI and E to the nth term. I enter a number in TermsJTextField, choose PI or E radio button (only one button can be active at a time), press calculate, and it's supposed to display the answer in the appropriate. However, when I press calculate, the application goes in a hang, and none of the buttons are responsive, even the x button. And the answer is never displayed.
Here's the code. I've narrowed down to the part that gives me a headache:
private void CalculateJButtonActionPerformed(java.awt.event.ActionEvent evt) {
final double MAX_VALUE = 10000; //Max value
double Start, End; //Star and end time
BigDecimal result = new BigDecimal ("0"); // Constants for result
BigDecimal Error = new BigDecimal ("0"); // And Error
DecimalFormat integerFormatter = new DecimalFormat("#0.");
Start = System.currentTimeMillis();
int Terms;
int count = 1;
boolean PIchecked = PiJRadioButton.isSelected();
boolean Echecked = EJRadioButton.isSelected();
double PI = 0;
double E = 1;
try
{
Terms = Integer.parseInt(TermsJTextField.getText());
if ((Terms <= 2) || (Terms >= 10000)) // This checks for the number of terms
{
throw new NumberFormatException();
}
else
{
if (PIchecked) // If Pi butoon is selected, do the following calculation
{
for (int i =1 ; 1 <= (Terms);i++)
{
count++;
result = result.add(new BigDecimal (Math.pow((-1.0),count)/(2*i-1)));
}
EJRadioButton.setSelected(false);
result = result.multiply(new BigDecimal (4.0));
Error = new BigDecimal(Math.abs(PI-result.doubleValue())/PI * 100.0);
}
else if (Echecked) // This calculates nth term for E
{
result = new BigDecimal("0");
long factorial = 1L;
for (int i = 1; i < Terms ; i++)
{
factorial *= i;
result = result.add(new BigDecimal(1.0/factorial));
}
result = result.add(new BigDecimal(1L));
Error = new BigDecimal(Math.abs(E-result.doubleValue())/E * 100.0);
PiJRadioButton.setSelected(false);
}
End = System.currentTimeMillis(); //Time in ms to calculate the answer
//Output
DecimalFormat Number = new DecimalFormat("#####0.##");
if (PIchecked)
{
EJTextField.setText("");
PIJTextField.setText(String.valueOf(result));
ErrorJTextField.setText(String.valueOf(Error + "%"));
}
else
{
PIJTextField.setText("");
EJTextField.setText(String.valueOf(result));
ErrorJTextField.setText(String.valueOf(Error + "%"));
}
PrintJButton.setEnabled(true);
PrintJMenuItem.setEnabled(true);
TimeJTextField.setText(String.valueOf(End-Start));
}
}
catch(NumberFormatException exp)
{
Object ERROR_MESSAGE = null;
JOptionPane.showMessageDialog(null, "Don't be silly; Enter a vaule between 2 and 10000",
"Input Error", JOptionPane.ERROR_MESSAGE);
TermsJTextField.selectAll();
TermsJTextField.setText("");
TermsJTextField.requestFocus();
}
}
It seems that your termination condition for your for-loop will never complete, as seen below:
for (int i =1 ; 1 <= (Terms);i++)
Switching it to the following should fix it (changed 1 to i):
for (int i = 1; i <= Terms; i++)

Logic behind multiplication method using a 1D Array of LongNumber class

I am having problems with the logic behind this multiplication method. It is using a 1D array of LongNumber. We can't use the Math class, must write our own logic. The two previous methods were addition and subtraction, I am having issues with how to setup the for loop in order to move one num index as we stay at the index of the other, and then changing to the next index of the number that wasn't moved.
This logic has been more confusing for me, addition and subtraction were all in once simple for loop and it was easy, with multiplication I cant figure out how to setup the loop so it only moves num index and not num2, so we can get the correct product.
public static Long_Number multiply(String num,String num2)
{
//data
String resultString3 = "";
Long_Number result3 = new Long_Number("");
int total, carry = 0, temp;
int v1 = 0, v2 = 0;
//set longest length to indexrange
int indexrange = num.length();
if(num2.length()>indexrange)
indexrange = num2.length();
//logic
for(int i = 0; i < indexrange; i++)
{
if(num.length()-1-i >= 0)
v1 = (num.charAt(num.length()-1-i)-'0');
else
v1 = 0;
if(num2.length()-1-i >= 0)
v2 = (num2.charAt(num2.length()-1-i)-'0');
else
v2 = 0;
sumofdigits = v1 * v2 + carry;
carry = sumofdigits % 10;
System.out.println(sumofdigits + "hi" + carry); //test print
}
result3.setNumber(resultString3);
return result3;
}

Loop a calculation a certain fixed amount

Does anyone know how I can loop through this calculation 7 times?
public static double[] getNumSeedsPerType(String[] treeTypes, int[] numTreesPerType, final double FIR_DIE) {
double numSeeds = 0;
double[] numSeedsPerType = new double[numTreesPerType.length];
for (int i = 0; i < treeTypes.length; i++) {
if (treeTypes[i].equalsIgnoreCase("fir")) {
// This part of the calculation
numSeeds = numTreesPerType[i] - (numTreesPerType[i] * FIR_DIE);
numSeedsPerType[i] = numSeeds + numTreesPerType[i];
}
}
return numSeedsPerType;
}
If my understanding of your code is correct you can do the following:
Use a for loop to do the calculation 7 times.
Inside the loop change this code:
numSeeds = numTreesPerType[i] - (numTreesPerType[i] * FIR_DIE);
to this (so you can keep the results of every calculation):
numSeeds += numTreesPerType[i] - (numTreesPerType[i] * FIR_DIE);

Java storing objects in a multidimensional array

I'm attempting to store objects in a multidimensional array in an attempt to save each position in a game boards 'state', however after the loop which is supposed to set each instance to it's own parameters they all end up the same variables. Did I not link the correct array or set it up wrong?
There's also a lot of "square.something should be accessed in a static way".
Is square.var or World[x][y].var the correct way for referencing the objects variables?
public static void generateMap() {
MapSquare[][] World = new MapSquare[10][10]; //2D array init.
//Choose a square for the home position.
Random homeRandom = new Random();
int HomeX = homeRandom.nextInt(10);
int HomeY = homeRandom.nextInt(10);
//Chooses a key room.
int KeyX = homeRandom.nextInt(10);
int KeyY = homeRandom.nextInt(10);
//Loop through the objects and set each's parameters.
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
MapSquare square = new MapSquare();
//World[i][j] = square;
//Calculate the level of the square from the distance to home.
int distX = HomeX - i;
int distY = HomeY - j;
int CalcX = Math.abs(distX); //Convert to positive if negative.
int CalcY = Math.abs(distY); //Convert to positive if negative.
//Generate contents of the square.
int newRandom = random.nextInt(5) + 1;
switch(newRandom) {
case 1: // Spawn a monster only.
{
square.monster = true;
square.treasure = false;
square.trap = false;
square.home = false;
square.peekable = false;
square.key = false;
square.mapLevel = CalcX + CalcY;
//Generate the monsters stats.
Monster monster = new Monster();
monster.setLevel(square.mapLevel);
monster.setMaxHealth(monster.getLevel() * 5);
monster.setHealth(monster.getMaxHealth());
monster.setDamage(monster.getLevel() * 2);
break;
}
}
}
}
//Generate home square.
World[HomeX][HomeY].monster = false;
World[HomeX][HomeY].treasure = false;
World[HomeX][HomeY].trap = false;
World[HomeX][HomeY].home = true;
World[HomeX][HomeY].peekable = true;
World[HomeX][HomeY].key = false;
World[HomeX][HomeY].mapLevel = 0;
World[HomeX][HomeY].visited = true;
}
The static keyword basically means that a method can be used independently of a specific instance of the class it is in. Such as the Math.abs(int i) function you are using, you don’t have to create an instance of the Math class to use it.
If you intend to use a class to store data it is generally a bad idea to include static methods as they would not be able to access that data.

Categories

Resources