Java out of bounds exception inside nested for loop - java

this may be an easy one, but I'm getting an out of bounds exception and I'm not sure how to fix it.
Basically, I am trying to create a "table" of integer fields so that I can use them to find if all of the values in the integer fields create a magic square. The nested for loop should create up to an 8x8 square, and it will create the first row of the square, but instead it gives me an out of bounds error.
The error occurs inside of the nested for loop where I'm adding the IntegerField to the GUI.
If anyone can help, that would be great. Let me know if you need more details.
import javax.swing.*;
import BreezySwing.*;
public class Interface extends GBFrame{
//Create integerField array to create input for magic square
public IntegerField[][] magicSquare;
//Create input button, integer field which sets size of square
public IntegerField squareSize;
public JButton inputSize;
//Create check square button
public JButton checkSquare;
//Label to output if there is a magic square
public JLabel squareLabel;
//Size of square variable
public int size;
//CalcSquare object
CalcSquare calc = new CalcSquare();
//Constructor for Square interface
public Interface()
{
squareSize = addIntegerField (0, 1, 1, 1, 1);
inputSize = addButton ("Input Size", 2, 1, 1, 1);
squareLabel = addLabel ("", 3, 1, 1, 1);
checkSquare = addButton ("Check Square", 4, 1, 1, 1);
}
//Creates IntegerFields on the GUI as needed.
public void createFields()
{
for (int i = 0; i <= size; i++)
{
for (int x = 0; x <= size; x++)
{
magicSquare = new IntegerField[i][x];
}
}
}
public void buttonClicked(JButton buttonObj)
{
if (buttonObj == inputSize)
{
size = squareSize.getNumber();
createFields();
for (int i = 0; i <= size; i++)
{
for (int x = 0; x <= size; x++)
{
magicSquare[i][x] = addIntegerField (0, i+1, x+1, 1, 1);
}
}
}
else if (buttonObj == checkSquare)
{
}
}
}

A for loop condition of i <= size Should always raise red flags since if i == size, you've gone beyond the size of the array or collection. Note that arrays and collections are 0 based and go from 0 to size - 1.
It should instead almost always be i < size

All your loops are iterating upto size which will cause ArrayIndexOutOfBoundException. The Array index starts from 0 to size-1. Here is one of such loop in your code:
for (int i = 0; i <= size; i++)
you need to iterate the loop only till size
for (int i = 0; i < size; i++)
Correct other loops accordingly

size is never initialized. And your <= should be < in the for loops.
In fact, if you're using size as a constant to set the size of your arrays, you should use i < size - 1 in for loops.

Related

Fill array with zero in random places

So, what I am trying to do is to fill a 2D array with zeros in random places a specific amount of times. Let's say that it has to be 20 zeros in an array of 90 places. What I have done so far is to declare a 2D array and fill it with random numbers. And my next thought was to simply choose random positions and replace them with zeros. Any idea how I could do that?
int[][] myboard = new int[9][9];
for (int i = 0; i < myboard.length; i++) {
for (int j = 0; j < myboard[i].length; j++) {
myboard[i][j] = (int) (Math.random() * 10);
}
}
It is a rather simple way to achieve the goal, but it should do the job. So you need to get the length of each row. After you have done that you can call a function that will give you a random number between some start point and the length of the row. Here is some code sample to show you what I mean:
import java.util.concurrent.ThreadLocalRandom;
import java.util.Arrays;
public class Example {
public static void main(String []args) {
int[][] myboard = new int[9][9];
for (int i = 0; i < myboard.length; i++) {
for (int j = 0; j < myboard[i].length; j++) {
// fill the row with random vals
myboard[i][j] = GetRandomNumber(0, myboard[i].length);
}
// sneak as much zeros as your heart content
int random = GetRandomNumber(0, myboard[i].length);
myboard[i][random] = 0;
}
System.out.println(Arrays.deepToString(myboard));
}
private static int GetRandomNumber(int min, int max) {
/*
min is the start point
max is the curr row len
*/
return ThreadLocalRandom.current().nextInt(min, max);
}
}
A pseudo code would look like:
while (num_zeros_filled < 20):
row = random()%total_rows
col = random()%total_cols
if (arr[row][col] == 0): # already filled in with 0
continue
else:
arr[row][col] = 0
num_zeros_filled += 1
This, however, could take infinite time theoretically if only those cells are generated which have already been filled with 0. A better approach would be to map the two-dimensional array into a 1-d array, and then sample out only from those cells which haven't been filled with 0 yet.

Why does this program not stop duplicates in the array?

I'm trying to write a program that generates six random integers, and return them to the user without any of the numbers being duplicates. Why do duplicates still get through?
I've searched it up on Google and tried a few of the results, but none of them seemed to work. I thought of my own method to try to solve this issue, by doing the following:
Using a for loop, I store one number at a time from drawnNums (the array with six random numbers) in numToCheck. There is also a variable numOfDuplicates which stores how many of that number it found. Using another for loop, I go through all the numbers in drawnNums and compare it with numToCheck, and add one to numOfDuplicates. It obviously finds itself, so I have an if statement that only redraws numbers if numOfDuplicates is >= 2. This is in the same function where I create the array, so it should create a new array and check through again, redrawing until there are no duplicates.
In my mind, this should stop duplicates from being returned, but it doesn't.
This is from class I have created to generate the array, and what I described above.
// Private function to draw one random number
private int drawNumber() {
return random.nextInt(maxNum) + 1;
}
// Function to randomly draw six numbers using drawNumber() and store in an array
int[] draw() {
int[] drawnNums = {0, 0, 0, 0, 0, 0};
for (int i = 0; i < drawnNums.length; i++) {
int draw = drawNumber();
drawnNums[i] = draw;
}
// Check if there are any duplicates in the array, if there are, redraw
int numOfDuplicates = 0;
for (int x = 0; x < drawnNums.length; x++) {
int numToCheck = drawnNums[x];
numOfDuplicates = 0;
for (int y = 0; y < drawnNums.length; y++) {
if (numToCheck == drawnNums[y]) {
numOfDuplicates++;
}
if (numOfDuplicates >= 2) {
draw();
}
}
break;
}
return drawnNums;
}
}
I expect that if there are duplicates in the array, the numbers will be redrawn until there is an array with no duplicates. But when running the program repeatedly, there are still some arrays with duplicates in them.
Your recursive call to draw is not returning a value. Should be
return draw();
The outer check loop exits early without completely checking the entire array for duplicates, remove the break. Check if x==y in the inner loop, do the duplicate check only if they are not.
Or in java 8, use a one liner to replace the entire thing.
new Random().ints(start, end).distinct().limit(number).toArray();
Ref - Random number generator without replacement?
You want to check for duplicates within your returnable Array before you add to it. In other words, as soon as the draw variable receives a new random value see if that value is already contained within the drawnNums array:
private int[] draw() {
int[] drawnNums = {0, 0, 0, 0, 0, 0};
boolean alreadyHave;
for (int i = 0; i < drawnNums.length; i++) {
int draw = drawNumber();
alreadyHave = false;
for (int j = 0; j < drawnNums.length; j++) {
if (draw == drawnNums[j]) {
alreadyHave = true;
i--;
break;
}
}
if (!alreadyHave) {
drawnNums[i] = draw;
}
}
return drawnNums;
}
If you want uniqueness, it's easiest to use a container that gives you uniqueness.
int[] draw() {
final int COUNT = 6;
// get unique numbers
Set<Integer> nums = new HashSet<>();
while (nums.size() != COUNT)
nums.add(drawNumber());
// convert to array as per original requirements
// though it would be simpler if we could just
// return a Collection<Integer>
int[] result = new int[COUNT];
int k = 0;
for (Integer num : nums)
result[k] = num;
return result;
}
Simpler, by a change of return type, with no loss of usefulness to the caller:
Collection<Integer> draw() {
final int COUNT = 6;
Set<Integer> nums = new HashSet<>();
while (nums.size() != COUNT)
nums.add(drawNumber());
return nums;
}

Value not changing correctly in array

I have the following method in one of my classes called Board. Board has an array of 120 Squares, which is another class from my program.
public class Board{
private Square[] square = new Square[120];
...
Each Square has an int row and an int column.
public class Square extends JButton{
public int row;
public int column;
...
The method itself is supposed to figure out what the row and column is for every Square inside
void setSquares() {
int ones;
int tenths;
Square s = new Square();
Insets squareMargin = new Insets(5, 5, 5, 5);
s.setMargin(squareMargin);
for (int i = 0; i < square.length; i++){
ones = getNdigit(i, 1);
tenths = getNdigit(i, 2);
//set row && set column
if ((tenths >= 2 && tenths <= 9) && (ones >= 1 && ones <= 8)){
s.row = tenths - 1;
s.column = ones;
} else{
s.row = 0;
s.column = 0;
}
square[i] = s;
System.out.println(square[0].toString());
}
So at the end of the method, I expect that square[34] has a row of 2 and a column of 4. However, the actual result is always the same as where the for loop ended (square[34] has a row and column of 0).
If the for loop was changed to
for (int i = 0; i < 55; i++){
then square[34] has a row of 4 and a column of 4.
You are creating only one instance of Square and use it throughout the for loop. Move the instantiation inside the for loop so each instance stored will be different.
To answer your question in the comment:
Square s = new Square();
Allocates some space in memory to store the Square instance (where you can set values to its members). so now s references that space in memory.
square[i] = s;
so now square[i] references that same space (thus having the same member values). so for every i all square[i] references to the same place (the same instance of Square). But if you allocate s one each iteration then s will reference a new square and each square[i] will reference a different Square instance

Java how to find the middle of a 2d array

I'm writing a function that tries to find the middle of a 2d array, and here's what I have so far:
int findMiddle(int[][] grid,int [] m) {
int[] list = new int[grid.length*grid[0].length];
int listPos = 0;
for(int i = 0 ; i < grid.length; i++) {
for(int j = 0; j < grid.length; j++) {
list[listPos++] = grid[i][j];
}
}
int middle = m.length/2;
if (m.length%2 == 1) {
return m[middle];
} else {
return (m[middle-1] + m[middle]) / 2.0;
}
}
Suppose I have an array of
{{0, 1, 2, 3},
{4, 5, 6, 7},
{8, 9, 0, 1}}
It should return 6, as it is integer division.
Also, the definition of middle in this code is the middle integer of the whole original array (needless to say if it is sorted or not).
How would I do this? ( my code also doesn't compile)
This compiles, and will give you the middle number in your sequence, or the average of the middle two if it splits the middle:
static double findMiddle(int[][] grid) {
int[] list = new int[grid.length*grid[0].length];
int listPos = 0;
for(int i = 0 ; i < grid.length; i++) {
for(int j = 0; j < grid[i].length; j++) {
list[listPos++] = grid[i][j];
}
}
int middle = list.length/2;
if ((list.length%2) == 1) {
return list[middle];
}
return (list[middle-1] + list[middle]) / 2.0;
}
However, I suspect you'll want to sort you numbers after you combine them into a single array, before you find the middle numbers. (as piyush121 commented)
Assuming your definition of 'median' is correct (the middle number of an odd length set or the average of the two middle numbers of an even length set), and if grid[][] is sorted, and if grid[][] is a square array (i.e. grid.length = grid[i].length for all i in 0..length-1, then you don't need to copy data to another array. The following should suffice:
static int findMiddle(int[][] grid) {
int l = grid.length;
if (l%2 == 1) {
return grid[l/2][l/2];
} else {
return (grid[l/2-1][l-1]+grid[l/2][0])/2;
};
Looking at your existing code it seems you are defining 'median' as the middle value in the matrix if all values were put into a single row-wise list. In other words you don't need to cope with odd numbers of rows (when two numbers from the same column are in the middle) or odd numbers of rows and columns (when there are four numbers in the middle).
If that definition is correct then you can cope with all the complexity of uneven rows by streaming all values and then selecting the middle ones.
For your interest, here's a Java 8 solution that does that:
int[] flat = Arrays.stream(grid).flatMapToInt(Arrays::stream).toArray();
double middle = Arrays.stream(flat).skip(flat.length / 2).limit(1 + flat.length % 2)
.average().getAsDouble();

Adding 26 objects to an array list, but only 13 are being added

I'm creating a "Deal or no deal" code assignment for school. I am trying to creating 26 "case" objects in my "cases" arraylist using a for loop, however when I try to test my code it will not let me access anything above index 13. I get an arraylist out of bounds error.
public void createCases()
{
int amount;
int counter1 = 1;
int amountFound;
int allzero;
//Make a list of possible winning amounts
int amounts[] = new int[26];
for(int i = 0; i <= 25; i++) {
amounts[i] = counter1;
counter1++;
}
//Copy the winning amounts from amounts to amountsRandom... randomly.
int amountsRandom[] = new int[26];
for(int i = 0; i <= 25; i++) {
do {
amountFound = (int)(Math.random() * 25);
} while(amountFound == 0);
amountsRandom[i] = amounts[amountFound];
amountFound = 0;
}
//Take the amounts in index order and make them part of the case objects in the array list.
for(int i = 0; i <= 25; i++) {
cases.add(new Case(i++ , amountsRandom[i-1]));
}
}
I declared my cases arraylist outside of this method so it can be accessed by the entire class.
You are incrementing i twice: once in the for loop, once in the constructor call.
In your for loop where you add the Case ojects to the cases arraylist
for(int i = 0; i <= 25; i++) {
cases.add(new Case(i++, amountsRandom[i-1]));
}
You are calling i++ two times, so i will iterate twice per loop. Because of this, it only loops through 13 times instead of 26. You might want to change it to new Case(i + 1, amountsRandom[i-1])

Categories

Resources