break resulting in an infinite for loop? - java

I'm making a project for an online course. I don't want the computer-generated coordinates(xOfCompShips, yOfCompShips) to repeat themselves or be the same as those inputted by the user(xOfPlayerShips, yOfPlayerShips). So in case, the same coordinates are generated the if statement would decrease the value of i and make the loop run once more, replacing the duplicated coordinates. By printing lines for debugging I found out that the break statement seems to break the for loop with k and the control goes back to the for loop with i and without any new values being assigned to xOfCompShips,yOfCompShips(or perhaps same values being reassigned to them), the control goes back to the for loop with k and again back to the for loop with i and it keeps going back and forth.
I tried removing the break statement but then if the first random coordinates are a duplicate pair, the array is accessed for index = -1.
for(int i = 0; i < xOfCompShips.length; i++) {
xOfCompShips[i] = (int)Math.floor(Math.random() * 10);
yOfCompShips[i] = (int)Math.floor(Math.random() * 10);
for(int k = 0; k < xOfPlayersShips.length; k++) {
if((xOfCompShips[i] == xOfCompShips[k] && yOfCompShips[i] == yOfCompShips[k])
|| (xOfCompShips[i] == xOfPlayersShips[k] && yOfCompShips[i] == yOfPlayersShips[k])){
i--;
break;
}
}
}
I expect new random values are to be assigned to xOfCompShips and yOfCompShips each the if statement is executed.

(int) Math.floor(Math.random() * C) is the wrong way to do it, this doesn't get you quite uniform output, and it's also needlessly complicated. Make an instance of java.util.Random (and don't keep recreating it; make one instance once, and reuse it), and call rnd.nextInt(10) on that.
you loop k from 0 to xOfPlayersShips, and then use k as index to xOfCompShips. I doubt that's right.
as part of your loop, you say: if (xOfCompShips[i] == xOfCompShips[k] && yOfCompShips[i] == yOfCompShips[k]) restart loop. if i and k are the same, obviously that is true. i starts at 0, k starts at 0.. 0 == 0.
A run with a debugger would have shown you this rather quickly.

Have you tried also breaking out of the outer loop (i.e. k--;), if I understand correctly (which I don't think I do), you're changing i over and over but k is always the same triggering the loop to change i more.
for(int i = 0; i < xOfCompShips.length; i++) {
xOfCompShips[i] = (int)Math.floor(Math.random() * 10);
yOfCompShips[i] = (int)Math.floor(Math.random() * 10);
for(int k = 0; k < xOfPlayersShips.length; k++) {
if((xOfCompShips[i] == xOfCompShips[k] && yOfCompShips[i] == yOfCompShips[k]) ||
(xOfCompShips[i] == xOfPlayersShips[k] && yOfCompShips[i] == yOfPlayersShips[k])){
i--;
**k--;**
break;
}
}
}

Related

Java function not working when called twice

public static int getMinor(int[][] mat, int r, int c) {
int minor = 0;
int[] min = new int[4];
int x = 0;
while (x <= 3) {
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (i != r && j != c && mat[i][j] != 100) {
min[x] = mat[i][j];
x += 1;
mat[i][j] = 100;
}
}
}
}
minor = min[0] * min[3] - min[1] * min[2];
return minor;
}
public static void main(String[] args) {
int[][] mat = getMatrix();
System.out.println(getMinor(mat, 0, 0));
System.out.println(getMinor(mat, 1, 1));
}
for some reason when I call getMinor function again the code stops working.
It prints the minor the first time but does not work when I call it again in the next line.
getMatrix function just gets the matrix.
Your code contains the potential for an infinite loop. It is possible for (x <= 3) to never become false, and so for your while loop to run forever. You haven't given your input matrix, but I assume that what is happening is that the first call to getMinor returns and so println prints the returned result, but then the execution goes into getMinor the second time and gets stuck...never comes out, and so the second println never occurs and the program never exits.
Yes, that's what's going on. I just made up an arbitrary matrix, and my run prints a 0 and then locks up in the second call to getMinor, going around and around in the while loop forever with if (i != r && j != c && mat[i][j] != 100) never being true, and so x never changing. This occurs because you're operating on the same matrix the second time, and the locations already set to 100 are sufficient to cause the while loop to never exit.
If you start with a fresh matrix the second time, this doesn't so easily occur. This code, at least with my sample matrix, completes:
int[][] mat = getMatrix();
System.out.println(getMinor(mat, 0, 0));
mat = getMatrix();
System.out.println(getMinor(mat, 1, 1));
Another potential problem with your code (I say potential because maybe you will never use the wrong parameters so that this happens) is if you pass in r and c values that are larger than the w/h bounds of the matrix, then the program crashes with an index out of bounds error because the if clause succeeds more than 4 times in a run through the matrix, and so you haven't allocated enough slots in the min array, and min[x] = mat[i][j]; goes bang!.
You've changed the value of "mat" in "getMinor", so 2ed call dose not have same input as the 1st one . (You may read this to figure out java's "pass by reference" VS "pass by value")
It's not a good practice to modify input within a function named as "getXXX"

Does order of conditions matter with multiple conditions in a while loop?

I was not able to find the answer to this question. I was working on an insertion sort method and it wouldn't properly execute:
public static <T extends Comparable<? super T>> void insertionSort(T[] array) {
int length = array.length;
T temp;
for (int i = 1; i < length; i++) { //start of unsorted
temp = array[i]; //save the element
int j = i-1;
while (temp.compareTo(array[j]) < 0 && j >= 0) { // while temp is less than array[j]
array[j+1] = array[j];
j--;
} //end of while
array[j+1] = temp; //as soon as temp is greater than array[j], set array[j] equal to temp
}
}
This returned an ArrayIndexOutOfBoundsException on the while loop line, but when I switched the conditions in the while loop around to this:
while (j >= 0 && temp.compareTo(array[j]) < 0)
it worked. I didn't think in Java the order of conditions in a while loop mattered to the program? This is very strange to me, as I've never seen or heard of order mattering in a statement with && since I assumed that the two while loop lines were equivalent. I was stuck wondering this for a while and couldn't find an answer.
Can someone explain why this is so?
Conditions are evaluated left to right.
Initially, for case j=-1, your code wasn't evaluating the second condition because the first one was throwing an ArrayIndexOutOfBoundsException exception.
while (temp.compareTo(array[j]) < 0 && j >= 0)
However when you switched the conditions like this:
while (j >= 0 && temp.compareTo(array[j]) < 0)
then for the same case (j=-1), since first condition becomes false, then regardless of the second value, the whole condition will always be false; and so the second condition won't be evaluated and hence no exception in this case.
Lets consider the following example:
boolean b = Condition_1 && Condition_2;
Now if the Condition_1 is always false then whatever the value of Condition_2, b will always be false. So when first condition is false of an 'and' then no need to check the value of second condition that is what exactly happened here.
It's exactly error if you use the condition while (temp.compareTo(array[j]) < 0 && j >= 0)
In Java, it checks condition && first and then checks || after.
In the condition && it checks in the order.
Therefore, in your case while (temp.compareTo(array[j]) < 0 && j >= 0), it check this condition temp.compareTo(array[j]) firstly. If j out of the array index, ==> you get error
When you change the condition to while (j >= 0 && temp.compareTo(array[j]) < 0), it check j>=0 firstly, if j = -1 the program cannot go further.

How does that for loop doesn't goes out of bounds with unidimensional array in JAVA?

Take a look :
int[] v = new int[10];
for (int i = 0; i < v.length; i++) {
for (int j = i + 1; j < v.length; j++) {
if (v[i] > v[j]) {
aux = v[i];
v[i] = v[j];
v[j] = aux;
}
}
}
This works perfecly. But can someone explain how?
How this array DOES NOT goes out of bounds even if I start j with i + 1 ? How does this works?
You have confused the initialization with condition. The syntax for for loop() is-
for(initialization; condition; updation)
{
statement(s)
}
So even if you start j from 1 ( j = i+1 and initial value of i = 0), j will update only till it is equal to the length of the array v i.e., 10. So the moment, j = 10 ( when i = 9), the control will come out of j for loop() and when it will transfer to i for loop(), i will be updated to 10, thus meeting it's condition and moving the control out of i for loop() also.
I think you need to go back to basics on for loops
a for loop can be defined as for(before starting;continue when true;do at end of pass))
So it doesn't matter what your start value is, as soon as j is equal to v.length it will stop. It just does 1 less loop that if you started at i.
Your for loops are made up of a variable to keep track, the condition and the iteration. In your code, the condition of the for loops states that the variable that is keeping track cannot go past the length of v. Therefore, during the sort (because that's what the code is), the inner loop compares all of v's values using j as the index to swap if they meet the if condition. The outer loop is just there to make sure that each index of v is checked and are in the right place.

Incrimenting value DOWN wont print out

Having an issue printing the results of i when I'm incrementing DOWN starting from startVal and ending at endVal with an increment of incVal.
the first if statement is printing correctly and I had THOUGHT that the second else if statement should be fairly similar however even though my original values; for EX: if startVal = 100, endVal = 10, and incVal = -1, it jumps to the else if statement correctly (tested with a basic print statement) but the for loop doesn't seem to work and not print out the results of i like it should.
if ((startVal < endVal) && (incVal >= 1))
{
for (int i = startVal; i <= endVal; i += incVal)
{
System.out.println(i);
}
}
// else if incrimenting down
else if((startVal > endVal) && (incVal <= -1))
{
for (int i = startVal; i <= endVal; i -= incVal)
{
System.out.println(i);
}
}
Is there something stupid I'm messing up here? I've tried different things inside the for loops to get i to print but it doesn't work the correct way..
It's because you didn't change the for loop in the else clause
for (int i = startVal; i >= endVal; i += incVal)
{
System.out.println(i);
}
edit: incValue should also be increasing since you have i=-1, thanks mstbaum
Your problem is that if (startVal > endVal) is true, your first iteration of your for loop will be be false because int i = startVal; i <= endVal, which evaluates in the first iteration as startVal <= endval.
You are also decrementing by a negative number (guaranteed by your incVal <= -1 condition), which will result in i actually because of i -= incVal.

Nested For loop incrementing after termination

I've got 2 for loops, one nested inside of another. They loop through a 2D array of buttons to get the source of each button thats been clicked using the action listener.
When the button is found I pass the position/array indexs of the button to an external method. However when the button is found from the array of buttons the first for loop evaluates its termination condition to FALSE but still increments the value of i. Leading to an off by one error. My code is in the standard action performed method, with "event" being the ActionEvent. buttons[][] is a JButton array defined as an instance variable. It is of size 10 x 10 and is already added to the panel.
int i = 0; //this will loop through the columns in the array
int j = 0; //loop through the rows
boolean locatedSource = false; //allows me to escape both loops
for(i = 0; !(locatedSource) && i < buttons.length; i++) //problem here, when i < buttons.length is FALSE i still gets incremented, leading to an off by one error
{
for(j = 0; !(locatedSource) && j < buttons.length; j++)
{
if(event.getSource() == buttons[i][j])
{
locatedSource = true;
break;
}
}
}
//do stuff with i and j in another method. Leads to array out of bounds error / off by one error
}
I should of mentioned, I'm not looking to solve this problem with the use of labels, they seem to be discouraged.
Explanation of the problem
The increment expression of a for loop is executed after each loop iteration not before. See the following quote from the Oracle Java tutorial:
The for statement provides a compact way to iterate over a range of values. Programmers often refer to it as the "for loop" because of the way in which it repeatedly loops until a particular condition is satisfied. The general form of the for statement can be expressed as follows:
for (initialization; termination;
increment) {
statement(s)
}
When using this version of the for statement, keep in mind that:
The initialization expression initializes the loop; it's executed once, as the loop begins.
When the termination expression evaluates to false, the loop terminates.
The increment expression is invoked after each iteration through the loop; it is perfectly acceptable for this expression to increment or decrement a value.
For loop solution
You can re-write your loop so that the increment is the first statement inside the loop.
for (i = 0; !(locatedSource) && i < buttons.length;) {
i++;
for (j = 0; !(locatedSource) && j < buttons.length;) {
j++;
if (event.getSource() == buttons[i][j]) {
locatedSource = true;
}
}
}
While Loop Version
Given that the loop variables are both initialised outside of the loop and you don't want to use a for-loop increment expression it might be clearer to rewrite the code to use while-loops as follows:
while (!(locatedSource) && i < buttons.length) {
i++;
while (!(locatedSource) && j < buttons.length) {
j++;
if (event.getSource() == buttons[i][j]) {
locatedSource = true;
}
}
}
Three possible solutions:
Explicitely set a "found" index and do not reuse your for loop indices.
Factor the searching out in an own method and return directly from the loop.
Decrement i by 1 after finishing the loops.
Use some boolean flag set it in inner loop and check it in the beginning of outer loop.
Here is code:
boolean found = false;
for (i = 0; i < 10; i++) // problem here, when i < buttons.length is FALSE i still gets
// incremented, leading to an off by one error
{
if (found) {
i--;
break;
}
for (j = 0; j < 5; j++) {
if (i == 5 && j == 3) {
found = true;
break;
}
}
//if (found) {
// break;
//}
}
Your code contains a comment "problem here, when i < buttons.length is FALSE i still gets incremented, leading to an off by one error", which is wrong in the ordering of the events.
First the cycle update block gets executed (like i++) and after that the condition is checked (like `i < buttons.length').
Meaning, that i == buttons.length is the correct state after the cycle ends without triggering the locatedSource condition.

Categories