Java: ArrayIndexOutOfBoundsException when trying to change position of rectangle [duplicate] - java

This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 7 years ago.
I am developing a Java game, and am currently writing a map maker. I can make the map and draw tiles, but i need to be able to change the position of those tiles so the character can see different locations of the map. When I try to change it, in the moveMap() method, It gives me this error:
Exception in thread "Thread-2" java.lang.ArrayIndexOutOfBoundsException: 570
at Base.moveMap(Base.java:88)
at Base.run(Base.java:55)
at java.lang.Thread.run(Unknown Source)
I have no idea why this is happening - could someone please help me understand the problem. Is there any alternate way to move the tiles?
Here is my code...
public class Base extends JPanel implements Runnable {
private static String[] line = {
"wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww",
"wwwwwwwwwwwwwwwwfffffffffffwwwwwwwwwww",
"wwwwwwffwwwwwwwwfwwwwwwwwwwwwwwwwwwwww",
"wwwwwwfffffffwwwfwwwwwwwwwwwwwwwwwwwww",
"wwwwwwffwwwffffffwwwwwwwwwwwwwwwwwwwww",
"wwwwwwffwwwffffffwwwwwwwwwwwwwwwwwwwww",
"wwwwwwfffffffwwwwwwwwwwwwwwwwwwwwwwwww",
"wwwwwwffwwwwwwwwwwwwwwwwwwwwwwwwwwwwww",
"wwwwwwffwwwwwwwwwwwwwwffffffffwwwwwwww",
"wwwwwwffwwwwwwwwwwwwwwwwwwwwffwwwwwwww",
"wwwwffffffwwwwwwwwwwwwwwwwwwffwwwwwwww",
"wwwwffffffffffffffffffffffffffwwwwwwww",
"wwwwffffffwwwwwwwwwwwwwwwwwwwwwwwwwwww",
"wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww",
"wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww",};
private Rectangle[] colRect;
private int tileWidth = 30;
private int tileHeight = 30;
public Base() {
colRect = new Rectangle[line.length * line[0].length()];
for (int i = 0; i < line.length; i++) {
for (int f = 0; f < line[i].length(); f++) {
colRect[counter] = new Rectangle(f * tileWidth, i * tileHeight,tileWidth, tileHeight);
if (counter != colRect.length) {
counter += 1;
}
}
}
}
public void moveMap(){
for(int i = 0; i <= colRect.length; i++){
colRect[i].setLocation(colRect[i].x+1, colRect[i].y+1);
}
}
}

You almost certainly mean this:
for (int i = 0; i < colRect.length; i++) {
Instead of this:
for(int i = 0; i <= colRect.length; i++){
Remember that if an array has length n, the indexes go from 0 to n - 1.

I would suggest you just to modify the accessor to your geometry, than the map itself. Because it looks like, the function moveMap could have some kind of "loop" behaviour
getLocation (int index, offset = 0){
int accIndex = (index + offset) % colRect.length;
// ... probably better to modify your data-structure to simplify the handling
}

Related

Problem with creating objects in a multi dimensional array [duplicate]

This question already has answers here:
What is a NullPointerException, and how do I fix it?
(12 answers)
Closed 4 years ago.
I currently have a problem with creating objects using two-dimensional arrays in Java.
I'ld like to display bricks on a playing board (like in the classic "BreakOut games), therefore I created a class "Stone" for the stone-objects, the constructor of the class is:
public Stone (Position pos, int value){
this.pos = pos;
this.type = type;
}
I also created a 2D-array (int) called "stoneTypes" for the pattern of the Stones, in which I saved a matrix from a JSON file.
I ld' now like to create Stone-objects in my class "Level" by using the values of the stoneTypes-matrix, which currently looks like this (I included an if-condition, so Stone-objects are only created for stoneTypes value >= 1):
private Stone[][] stones = new Stone[25][20];
private int[][] stoneTypes;
JSONReader reader = new JSONReader("res/Level" + levelnr +".json");
stoneTypes = reader.getStones2DArray();
for (int w = 0; w < stoneTypes.length; w++) {
for (int h = 0; h < stoneTypes[w].length; h++) {
if (stoneTypes [w][h] >= 1) {
Position pos = new Position(width * w, height * h);
this.stones[w][h] = new Stone(pos, stoneTypes[w][h]);
}
}
}
I also included a get-Method for the Stone-array, so I could use it to draw the Stones in my "Field" class:
public Stone[][] getStones(){
return this.stones;
}
The method for drawing the Stones in my "Field" class currently looks like this:
private void drawStones(Graphics2D g2) {
stones = view.getGame().getLevel().getStones();
for (int i = 0; i < stones.length; i++) {
for (int j = 0; j < stones[i].length; j++) {
*** int x_position = (int) stones[i][j].getPosition().getX(); ***
int y_position = (int) stones[i][j].getPosition().getY();
g2.fillRoundRect(x_position, y_position,
(int) ((double)Constants.SCREEN_WIDTH/Constants.SQUARES_X)-2,
(int) ((double)Constants.SCREEN_HEIGHT/Constants.SQUARES_Y)-2 ,1,1);
System.out.println(x_position);
}
}
}
Eclipse doesn't show any syntax errors but I do receive a NullPointerException at the spot I marked with the ***, as soon as I start the programm. I am not sure if my get-Method isn't implemented correctly or if the process of creating new Stone-objects is simply wrong. I tried hundreds of things but couldn't find a solution, I hope you guys can help me.
Thx in advance, Scoopa!
Here:
if (stoneTypes [w][h] >= 1) {
Position pos = new Position(width * w, height * h);
this.stones[w][h] = new Stone(pos, stoneTypes[w][h]);
}
You are only creating new stones when that condition is met. All other fields will stay with their default initial value. And that would be: null.
When you do that, you can't just go in (unconditionally) and do:
int x_position = (int) stones[i][j].getPosition().getX()
You would need a
if (stones[i][j] != null)
to guard such accesses!

Array size declaration

I've posted my code below. I am having a problem on the line declaring the array wrongAnswers. I've been able to get my code working before, but the problem is that some person took it upon themselves to delete all my files. I was able to get it working without using List or ArrayList. I just want to understand how I can get this working now before I try using either of those other methods. I understand that Java arrays are immutable. However, I was still somehow able to get it to work before. If someone could help me figure out what I did previously, I would be most greatful.
private Scanner keyboard = new Scanner(System.in);
private final String[] testAnswers = {
"B","D","A","A","C",
"A","B","A","C","D",
"B","C","D","A","D",
"C","C","B","D","A"};
private String[] studentAnswers = new String[20];
/*
private String[] studentAnswers = {
"B","D","A","A","C",
"A","B","A","C","D",
"B","C","D","A","D",
"C","C","B","D","A"};
*/
private int[] wrongAnswers;
private int answeredCorrectly = 0;
public void getStudentAnswers() {
for(int x = 0; x < 20; x++) {
do {
System.out.print("Enter answer for #" + (x + 1) + " : ");
this.studentAnswers[x] = keyboard.next().toUpperCase();
if (!"A".equals(this.studentAnswers[x]) &&
!"B".equals(this.studentAnswers[x]) &&
!"C".equals(this.studentAnswers[x]) &&
!"D".equals(this.studentAnswers[x])) {
System.out.println("Invalid input.");
}
} while(!"A".equals(this.studentAnswers[x]) &&
!"B".equals(this.studentAnswers[x]) &&
!"C".equals(this.studentAnswers[x]) &&
!"D".equals(this.studentAnswers[x]));
}
}
public int totalCorrect() {
int arrayLocation = 0;
for(int x = 0; x < 20; x++) {
if (this.studentAnswers[x].equals(this.testAnswers[x]))
this.answeredCorrectly++;
else
this.wrongAnswers[arrayLocation++] = x;
}
return this.answeredCorrectly;
}
public int totalIncorrect() {
return 20 - this.answeredCorrectly;
}
public boolean passed() {
return this.answeredCorrectly >= 15;
}
public void questionsMissed() {
if(this.answeredCorrectly != 20) {
for(int x = 0; x < this.wrongAnswers.length; x++) {
System.out.println(this.wrongAnswers[x]);
}
}
}
If code is well written, saving space (which is what you are trying to do) will usually cost performance and vice versa. You can achieve what you want, but you'll lose performance, as you'll see.
I find deduction to be useful when solving similar problems. Conditions:
1) Arrays are immutable
2) You want to allocate the exact amount of space that you need
Point 2 poses a question: how do you know how much space you need? Obvious answer: know how many (in)correct answers you have. Following from there you can do:
public int totalCorrect() {
for(int x = 0; x < 20; x++) {
if (this.studentAnswers[x].equals(this.testAnswers[x]))
this.answeredCorrectly++;
}
this.wrongAnswers = int[20 - this.answeredCorrectly];
// Here you want to create your wrongAnswers, but you have to go over
// the same array twice...
int arrayLocation = 0;
for(int x = 0; x < 20; x++) {
if (!this.studentAnswers[x].equals(this.testAnswers[x]))
this.wrongAnswers[arrayLocation++] = x;
}
return this.answeredCorrectly;
}
There are probably more ways to do something similar and achieve better performance too. At first sight they seem to me like bad approaches and I'd use a List, as has been proposed already, or perhaps a Set, but who knows...
private int[] wrongAnswers = new int [20];

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 1? [duplicate]

This question already has answers here:
What causes a java.lang.ArrayIndexOutOfBoundsException and how do I prevent it?
(26 answers)
Closed 7 years ago.
So, I've been doing this java class for several months now, and I've been assigned a project before the end of the year. I'm trying to rewrite some old code to use vectors and arrays, but... I get the topic title error. Here is the relevant code:
public static double VectorX(int len, double angle) {
return Math.cos(angle)*len;
}
public static double VectorY(int len, double angle) {
return Math.sin(angle)*len;
}
public static class Projectile {
public int x;
public int y;
public double angle;
public int speed;
public boolean Player;
}
...
public static Projectile[] Shoot = new Projectile[0];
public static double RadianAngle(int x1, int y1, int x2, int y2) {
return Math.atan2(x2-x1, y2-y1);
}
...
for (int i = 1; i <= Shoot.length; i++)
{
Shoot[i].x += VectorX(Shoot[i].speed, Shoot[i].angle);
Shoot[i].y += VectorY(Shoot[i].speed, Shoot[i].angle);
}
...
if (Cooldown == 75 || Cooldown == 25)
{
Projectile Hey = new Projectile();
Hey.x = EX;
Hey.y = EY;
Hey.Player = false;
Hey.speed = 2;
Hey.angle = RadianAngle(Hey.x, Hey.y, X, Y);
Projectile[] Shoot2 = new Projectile[Shoot.length + 1];
for (int l = 0; l <= Shoot.length - 1; l++)
{
Shoot2[l] = Shoot[l];
}
Shoot2[Shoot2.length - 1] = Hey;
Shoot = Shoot2;
}
I've no idea what is going on. I imported these Vector functions from a C#-based language that I am well versed in, but translated them to java. I am getting the error at
Shoot[i].x += VectorX(Shoot[i].speed, Shoot[i].angle);
Shoot[i].y += VectorY(Shoot[i].speed, Shoot[i].angle);
Could you guys give me a hand?
You're getting an ArrayIndexOutOfBoundsException because you are initializing the Shoot array with a size of 0 :
public static Projectile[] Shoot = new Projectile[0];
so the call to
Shoot[0].x += VectorX(Shoot[0].speed, Shoot[0].angle);
in your loop is invalid.
for (int i = 1; i <= Shoot.length; i++)
should be
for (int i = 0; i < Shoot.length; i++)
the reason why
int[] arr = new int[]{ 0, 1, 2 };
arr.length will now equal 3, my array does not have an index at 3, instead, it has indexes at 0, 1, and 2.
Your definition for the shoot array creates an array of length 0: Shoot = new Projectile[0];
Yet when you iterate over the array, you are setting the bounds of your loop variable incorrectly:
for (int i = 1; i <= Shoot.length; i++)
Arrays are zero-indexed (meaning an array of length 1 will have index [0] and no more). So starting your loop index at 1 (int i = 1) is bad to begin with.
Then you are looping too far. Say you have 3 elements in your array, the indexes will be 0, 1 & 2. And your array.length will be 3, but you never want to index 3. So your loop condition needs to be < array.length, not <= array.length.

ArrayList out of bounds exception? [closed]

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 9 years ago.
Improve this question
I am getting an arraylist out of bounds exception: Index 4999, Size 4999 in this method:
for (int y = 0; y < trees.getHeight() - 1; ++y) {
for (int x = 0; x < trees.getWidth() - 1; ++x) {
int c = trees.getRGB(x, y);
Color color = new Color(c);
if (color.getRed() == 0 && color.getGreen() == 255 && color.getBlue() == 0) {
treePosB.add(new Vector2f(x, y));
}
}
}
int randX = 0;
int randZ = 0;
boolean canPlace = false;
for (int i = 0; i < treesAr.size() - 1; ++i) {
randX = randInt(-terrain.getTerrainSize(), terrain.getTerrainSize());
randZ = randInt(-terrain.getTerrainSize(), terrain.getTerrainSize());
treesAr.get(i).setLocalTranslation(randX, terrain.getHeight(new Vector2f(randX, randZ)) - (40 + 1.0f), randZ);
for (int x = 0; x < treePosB.size() - 1; ++i) {
//FOLLOWING LINE CAUSES ERROR
if (treesAr.get(i).getLocalTranslation().x == treePosB.get(x).x && treesAr.get(i).getLocalTranslation().y == treePosB.get(x).y) {
canPlace = true;
continue;
}
}
if (canPlace) {
treeNode.attachChild(treesAr.get(i));
} else {
}
}
Im not sure whats causing this, i have changed the for loops to include a ArrayList.size - 1 to adjust for this, because i knew it would happen, but it still happens. The trees ArrayLIst is created like so:
treesAr = treeGen.generate(am);
Texture tex1 = Main.assetManager.loadTexture("Textures/Terrain/Trees/Trees1.png");
BufferedImage trees = ImageToAwt.convert(tex1.getImage(), false, true, 0);
public ArrayList<Geometry> generate(int amount) {
ArrayList trees = new ArrayList();
Geometry tree = (Geometry) Main.assetManager.loadModel(
"Models and Textures/Landscape/Trees/Pine.obj");
for (int i = 0; i < amount - 1; ++i) {
Geometry treeI = tree.clone();
trees.add(treeI);
}
return trees;
}
What this is doing, is load an image, and check the image for green pixels and creates an arraylist with vecotrs that represent the position of each pixel.
It then loads the trees, and goes through a for loop and checks the trees randomized position. If the tree is within the pixel area, they are added to the scene, otherwise nothing happens.
This allows me to draw an image and draw out where the trees are allowed to spawn.
for (int x = 0; x < treePosB.size() - 1; ++i) {
You mistyped this loop (x -> i). It increments i infinitely until it exceeds the size of the list.

How to create a number generator that will only pick a number 1 time?

I am creating a concentration game.
I have an buffered image array where I load in a 25 image sprite sheet.
public static BufferedImage[] card = new BufferedImage[25];
0 index being the card back. and 1 - 24 being the values for the face of the cards to check against if the cards match.
What I am tying to do is this I will have 4 difficulties Easy, Normal, Hard, and Extreme. Each difficulty will have a certain amount of cards it will need to draw and then double the ones it chosen. for example the default level will be NORMAL which is 12 matches so it need to randomly choose 12 unique cards from the Buffered Image array and then double each value so it will only have 2 of each cards and then shuffle the results.
This is what I got so far but it always seems to have duplicates about 99% of the time.
//generate cards
Random r = new Random();
int j = 0;
int[] rowOne = new int[12];
int[] rowTwo = new int[12];
boolean[] rowOneBool = new boolean[12];
for(int i = 0; i < rowOneBool.length; i++)
rowOneBool[i] = false;
for(int i = 0; i < rowOne.length; i++){
int typeId = r.nextInt(12)+1;
while(rowOneBool[typeId]){
typeId = r.nextInt(12)+1;
if(rowOneBool[typeId] == false);
}
rowOne[i] = typeId;
j=0;
}
the 3 amounts I will be needing to generate is Easy 6, Normal 12, and Hard 18 extreme will use all of the images except index 0 which is the back of the cards.
This is more or less in the nature of random numbers. Sometimes they are duplicates. You can easily factor that in though if you want them to be more unique. Just discard the number and generate again if it's not unique.
Here's a simple method to generate unique random numbers with a specified allowance of duplicates:
public static void main(String[] args) {
int[] randoms = uniqueRandoms(new int[16], 1, 25, 3);
for (int r : randoms) System.out.println(r);
}
public static int[] uniqueRandoms(int[] randoms, int lo, int hi, int allowance) {
// should do some error checking up here
int range = hi - lo, duplicates = 0;
Random gen = new Random();
for (int i = 0, k; i < randoms.length; i++) {
randoms[i] = gen.nextInt(range) + lo;
for (k = 0; k < i; k++) {
if (randoms[i] == randoms[k]) {
if (duplicates < allowance) {
duplicates++;
} else {
i--;
}
break;
}
}
}
return randoms;
}
Edit: Tested and corrected. Now it works. : )
From what I understand from your question, the answer should look something like this:
Have 2 classes, one called Randp and the other called Main. Run Main, and edit the code to suit your needs.
package randp;
public class Main {
public static void main(String[] args) {
Randp randp = new Randp(10);
for (int i = 0; i < 10; i++) {
System.out.print(randp.nextInt());
}
}
}
package randp;
public class Randp {
private int numsLeft;
private int MAX_VALUE;
int[] chooser;
public Randp(int startCounter) {
MAX_VALUE = startCounter; //set the amount we go up to
numsLeft = startCounter;
chooser = new int[MAX_VALUE];
for (int i = 1; i <= chooser.length; i++) {
chooser[i-1] = i; //fill the array up
}
}
public int nextInt() {
if(numsLeft == 0){
return 0; //nothing left in the array
}
int a = chooser[(int)(Math.random() * MAX_VALUE)]; //picking a random index
if(a == 0) {
return this.nextInt(); //we hit an index that's been used already, pick another one!
}
chooser[a-1] = 0; //don't want to use it again
numsLeft--; //keep track of the numbers
return a;
}
}
This is how I would handle it. You would move your BufferedImage objects to a List, although I would consider creating an object for the 'cards' you're using...
int removalAmount = 3; //Remove 3 cards at random... Use a switch to change this based upon difficulty or whatever...
List<BufferedImage> list = new ArrayList<BufferedImage>();
list.addAll(Arrays.asList(card)); // Add the cards to the list, from your array.
Collections.shuffle(list);
for (int i = 0; i < removalAmount; i++) {
list.remove(list.size() - 1);
}
list.addAll(list);
Collections.shuffle(list);
for (BufferedImage specificCard : list) {
//Do something
}
Ok, I said I'd give you something better, and I will. First, let's improve Jeeter's solution.
It has a bug. Because it relies on 0 to be the "used" indicator, it won't actually produce index 0 until the end, which is not random.
It fills an array with indices, then uses 0 as effectively a boolean value, which is redundant. If a value at an index is not 0 we already know what it is, it's the same as the index we used to get to it. It just hides the true nature of algorithm and makes it unnecessarily complex.
It uses recursion when it doesn't need to. Sure, you can argue that this improves code clarity, but then you risk running into a StackOverflowException for too many recursive calls.
Thus, I present an improved version of the algorithm:
class Randp {
private int MAX_VALUE;
private int numsLeft;
private boolean[] used;
public Randp(int startCounter) {
MAX_VALUE = startCounter;
numsLeft = startCounter;
// All false by default.
used = new boolean[MAX_VALUE];
}
public int nextInt() {
if (numsLeft <= 0)
return 0;
numsLeft--;
int index;
do
{
index = (int)(Math.random() * MAX_VALUE);
} while (used[index]);
return index;
}
}
I believe this is much easier to understand, but now it becomes clear the algorithm is not great. It might take a long time to find an unused index, especially when we wanted a lot of values and there's only a few left. We need to fundamentally change the way we approach this. It'd be better to generate the values randomly from the beginning:
class Randp {
private ArrayList<Integer> chooser = new ArrayList<Integer>();
private int count = 0;
public Randp(int startCounter) {
for (int i = 0; i < startCounter; i++)
chooser.add(i);
Collections.shuffle(chooser);
}
public int nextInt() {
if (count >= chooser.size())
return 0;
return chooser.get(count++);
}
}
This is the most efficient and extremely simple since we made use of existing classes and methods.

Categories

Resources