Fixing Index Out Of Bounds Exception - java

I have a problem with array indexing. The code is supposed to move objects of type Ant around a 20x20 grid.
public class Test {
Organism[][] grid = new Organism[20][20];
public static void main(String[] args) {
for (int i = 0; i < 20; i++){
for (int j = 0; j < 20; j++){
if(grid[i][j] instanceof Ant){
int xpos = i;
int ypos = j;
grid[i][j].move(xpos, ypos);
grid[i][j].breed(xpos, ypos);
}
}
}
}
Class Ant extends Organism, class Organism extends Test.
public class Ant extends Organism{
public void move(int xpos, int ypos){
Random rand = new Random();
int direction = rand.nextInt(3);
if(direction == 0){
if(grid[xpos][ypos + 1] == null && xpos <20 && ypos <20)
{
grid[xpos][ypos] = grid[xpos][ypos];
grid[xpos][ypos] = null;
{
}
}
}
The method move is supposed to choose a random direction on the grid and move the Ant there if the adjoining space is empty. It also cannot go outside the 20x20 grid. (There are three more if loops for the other directions).
If I change the sixth line in the move method to:
if(grid[xpos][ypos] == null && xpos <20 && ypos <20)
Then no error is thrown.
I hesitate to post this because its probably a small error on my part but I have been staring at this for several hours.
Assistance is greatly appreciated.

The operands for an && are evaluated from left to right, and the evaluation stops if one of them evaluates to false. So if one or more of the operands are potentially dangerous (such as an array lookup that might go out of bounds), and some of the other operands are supposed to protect against this, the protection operands need to go first. Also, you need to check the indices you're actually using, namely xpos and ypos + 1, and you forgot to use ypos + 1 in the assignment that moves the ant:
if (xpos < 20 && ypos + 1 < 20 && grid[xpos][ypos + 1] == null) {
grid[xpos][ypos + 1] = grid[xpos][ypos];
grid[xpos][ypos] = null;
}
(And, assuming that xpos and ypos are valid indices, you don't need to check xpos.)

Related

How to change RGB colour depending on mouse position in Processing3?

I am writing a little program in Processing3 that enables me to change the background to a specific colour RGB code stored in arrays. Each vale for R, G and B is stored in a separate array.
Changing the mouse horizontal position changes the colour of the background.
However this solutions code is quite repetitive, and there is a lot of if/else statements. I want to use a for() loop to simplify the code and make it less repetitive. However, i am struggling to include the mouse position variable in the for() loop. Is there to simplify this code using a for() loop and somehow map the mouse position to access array items? This is the code I have right now:
int[] r = {255,249,240,233,227};
int[] g = {115,138,157,173,187};
int[] b = {0,18,63,94,120};
void setup() {
size(500, 500);
}
void draw() {
int x = mouseX;
if(x >= 0 && x <=100) {
background(r[0], g[0], b[0]);
}
else if (x >= 101 && x <= 200){
background(r[1], g[1], b[1]);
}
else if (x >= 201 && x <= 300){
background(r[2], g[2], b[2]);
}
else if (x >= 301 && x <= 400){
background(r[3], g[3], b[3]);
}
else {
background(r[4], g[4], b[4]);
}
}
I wish to simplify the code to something more like this:
int[] r = {255,249,240,233,227};
int[] g = {115,138,157,173,187};
int[] b = {0,18,63,94,120};
void setup() {
size(500, 500);
}
void draw() {
for(int i=0; i<r.length; i++) {
background(r[i],g[i],b[i]);
}
}
However, I don't know how to change this code in a way, that the background colour would change depending on mouse horizontal position, as it is shown in the first example.
Thank you for your reply and help!
If your steps between your different values are 100, then you can just divide the input X value by 100. Integer division will take care of the rest.
The if statement is just to make sure it stays within the bounds of your array.
int mouseX = ...;
int i = mouseX / 100;
if(i < r.length && i < g.length && i < b.length)
{
background(r[i], g[i], b[i]);
}

Why are my intlist values not increasing, or why doesn't the ellipse() function respond to it?

javascript code in processing 3.5.3 not working, not sure why. It's supposed to create circles and have them bounce around the screen, instead it makes the right amount of circles but they don't move. It seems like intlist.set() isn't working, but I'm not sure why. Help would be appreciated.
import javax.swing.JOptionPane;
int x = 200;
int y = 150;
int b = 50;
float slope = -1;
int numOfCircles = 10;
IntList initPosX = new IntList();
IntList initPosY = new IntList();
IntList exes = new IntList();
IntList whys = new IntList();
IntList xSpeeds = new IntList();
IntList ySpeeds = new IntList();
void setup()
{
numOfCircles = int(JOptionPane.showInputDialog(frame, "How many circles ya want?"));
size(800,400);
for(int i = 0; i < numOfCircles; i++)
{
int toAddX = int(random(0,400));
initPosX.append(toAddX);
int toAddY = int(random(0,300));
initPosY.append(toAddY);
exes.append(0);//(int(random(-30,30)));
whys.append(0);//(int(random(-30,30)));
xSpeeds.append(1);
ySpeeds.append(1);
}
}
void draw()
{
background(100,100,100,255);
for(int i = 0; i < numOfCircles; i++)
{
ellipse(exes.get(i) + initPosX.get(i), whys.get(i) + initPosY.get(i), 20, 20);
exes.set(i, i + xSpeeds.get(i));
whys.set(i, i + ySpeeds.get(i));
if(exes.get(i) > width || exes.get(i) <= 0)
{
print("side wall hit");
xSpeeds.set(i, i*= slope);
}
if(whys.get(i) > height || whys.get(i) <= 0)
{
print("roof hit");
ySpeeds.set(i, i*= slope);
}
}
}
The problem is at those lines:
exes.set(i, i + xSpeeds.get(i));
whys.set(i, i + ySpeeds.get(i));
What you want to do there, is add the speed to the current value of exes/whys at the index i.
But what you are actually doing is set them to the index + the speed.
Since the index is never going to change, neither are the positions.
To fix this, replace it with this:
exes.set(i, exes.get(i) + xSpeeds.get(i));
whys.set(i, whys.get(i) + ySpeeds.get(i));
Update
When changing just this, your code still won't work properly, because the collision detection:
if(exes.get(i) > width || exes.get(i) <= 0)
{
print("side wall hit");
xSpeeds.set(i, i*= slope);
}
if(whys.get(i) > height || whys.get(i) <= 0)
{
print("roof hit");
ySpeeds.set(i, i*= slope);
}
does not detect collision for the actual position, because that would be the position (exes, whys) + the initPos's, so it should be
if (exes.get(i) + initPosX.get(i) > width || exes.get(i) + initPosX.get(i) <= 0)
{
//the code
}
if (whys.get(i) + initPosY.get(i) > height || whys.get(i) + initPosY.get(i) <= 0)
{
//the code
}
If you were to start it now however, you would get an error. That is because you changing to something negative. instead of i*= slope just use int(i * slope) (because int * float returns a float, you have to convert the result to an int by using int()).
Furthermore, you again don't actually want the index, but the current value at the index:
xSpeeds.set(i, int(xSpeeds.get(i) * slope); //the same for ySpeeds

Java change long if statement into for loop

I have an if statement that looks like this:
if (pan[x + 1][y + 1].getBackground() == TeamColor &&
pan[x + 1][y].getBackground() == TeamColor &&
pan[x + 1][y -1].getBackground() == TeamColor &&
pan[x][y - 1].getBackground() == TeamColor &&
pan[x - 1][y - 1].getBackground() == TeamColor &&
pan[x - 1][y].getBackground() == TeamColor &&
pan[x - 1][y + 1].getBackground() == TeamColor &&
pan[x][y + 1].getBackground() == TeamColor) {
// do something
}
The goal is to check every item (in a 2d array) around the current x and y values and make sure they are the correct color.
I assume there is a simple way to do such. I would assume creating a for loop would solve the problem by iterating through each item but unfortunately was not able to think of a way to do this because the items are not all in sequence.
NOTE: i found many other posts on stackoverflow that where titled "solution for very long if statement" unfortunately they were in different programing languages (such as python, android and javascript)
NOTE 2: this is Not a duplicate of this post. It was a question of strings and regex and unfortunately not the solution to my problem
Hopefully someone will have an answer!
Try something like this:
boolean match = true;
for (int dx = -1; match && (dx < 2); ++dx) {
for (int dy = -1; match && (dy < 2); ++dy) {
if (dx != 0 || dy != 0) {
match = pan[x+dx][y+dy].getBackground() == TeamColour;
}
}
}
if (match) {
// do something
}
Basically, you want to check offsets -1, 0 and 1 in each direction, so we have two for loops, each producing those offsets in one dimension. We then check the array element corresponding to each offset, and keep track using the match variable.
Note though that, like the original code, this will fail near boundaries (e.g. if x == 0). This can be fixed if necessary.
It is possible, of course, to instead have the loops run over the actual indices to check (e.g. for (int x2 = x-1; x2 < x+2; ++x)). It's much the same in the end.
for (int a = x-1;a <= x+1;a++)
{
if (a < 0 || a >= pan.length) continue;
for (int b = y-1; b <= y+1; b++)
{
if (b < 0 || b >= pan[a].length) continue;
if (a == x && b == y) continue;
if (pan[a][b].getBackground() != TeamColor)
return false;
}
}
return true;
I can propose two ways :
1) Full object way
You could introduce a custom class Coordinate that holds two values : the x and y coordinates.
Create a List of Coordinate where you had the Coordinate element you want to test and iterate on it to achieve your need.
public class Coordinate{
private final int x;
private final int y;
public Coordinate(int x, int y){
this.x = x;
this.y = y;
}
public getX(){
return x;
}
public getY(){
return y;
}
}
And you can use it :
List<Coordinate> coordinates = new ArrayList<>();
coordinates.add(new Coordinate(1,1));
coordinates.add(new Coordinate(1,0));
coordinates.add(new Coordinate(1,-1));
coordinates.add(new Coordinate(0,-1));
coordinates.add(new Coordinate(-1,-1));
coordinates.add(new Coordinate(-1,0));
coordinates.add(new Coordinate(-1,1));
coordinates.add(new Coordinate(0,1));
// you can also init them with a loop
boolean isMatched = true;
for (Coordinate coordinate : coordinates){
if (pan[x + coordinate.getX()][y + coordinate.getY()].getBackground() != TeamColor){
isMatched = false;
break;
}
}
The object way is more verbose but it has the advantage to expose rules.
So you can read and change it easily.
Suppose, the rules to check become more complex, it becomes very valuable.
2) Shorter code way
It is the same logical even by inlining values of Coordinate and by ignoring the specific case that you don't want to test (no change case).
boolean isMatched = true;
for (int xDelta = -1; xDelta <=1; xDelta++){
for (int yDelta = -1; yDelta <=1; yDelta++){
// as you don't want to test if no change
if (yDelta == 0 && xDelta ==0){
continue;
}
if (pan[x + xDelta][y + yDelta ].getBackground() != TeamColor){
isMatched = false;
break;
}
}

Trying to draw axes for Quadrant I, getting Quadrant IV instead

Currently, I am trying to create a program that draws a square anywhere in a 15x15 Quadrant I (Coordinate plane) grid. I am stuck on trying to get the axes displaying correctly.
This is the code I have thus far:
import java.util.Scanner;
public class Question2square {
public static void main(String[] args) {
// Axis variables
int yAxismin = 0;
int yAxismax = 15;
int xAxismin = 0;
int xAxismax = 15;
//Loop through all coordinates on plane using for loops
for(int y = yAxismin; y <= yAxismax; y++)
{
for(int x = xAxismin; x <= xAxismax; x++)
{
//Draw the axis
if (!Axis(x,y).equals("")) {
System.out.print(Axis (x,y));
}
}
System.out.println("");
}
}
// This method draws the 15x15 axis
public static String Axis(int x, int y)
{
// Each if and else if statement dictates what symbol needs to go where for the axes
// If there is nothing to be drawn, there will simply be a blank space
if (x == 15 && y== 0) return ">";
else if(x == 0 && y == 15) return "^";
else if (x == 0 && y == 0 )return ".";
else if(x == 0 && y >= 0) return "|";
else if(x >= 0 && y==0) return "-";
else return "";
}
/*
// Method to be used to draw actual square
public static ... drawSquare(...) {
}
*/
}
Unfortunately, instead of drawing the 'L' shaped axes I desire, it displays an 'r' shape instead. I'm trying to figure out how to display the axis properly.
I tried flipping the for loops but that didn't help. I don't see what else could be inhibiting this.
Try reversing the y loop:
for(int y = yAxismax; y >= yAxismin; y--) ...
As your loop prints lines to the console from "top to bottom" and then "left to right", you want your greatest value of y to come first and your least value of x to come first. Therefore you only need to reverse the y loop to go from yAxismax to yAxismin. The result (for limits of 3 and not 15 is then:
^
|
|
.-->

java: tetris random block generated upon row clear

I'm trying to make the game Tetris in java.
I've gotten it to the point where:
a new block is generated when it hits the floor or its y+1 is not null (meaning there's another block under it)
public void collisionCheck(int x, int y) {
if (activetile.getY() == this.height-2 || getTileAt(x, y+1) != null) {
activetile = new Tile(this, 0, 0);
}
}
A row clears when the bottom row is full of non-null values, or the Tetris pieces (for y = 4 (the floor), loop through x till x = 4 and check if all non-null)
public void checkBottomFull(int x, int y) {
while (getTileAt(x,y) != null) {
say("(" + x + ", " + y +")");
if (x == 3) {
say("row is full");
//replace full row with tiles from above
for (int i = 0; i < 4; i++) {
for (int j = 5; j > 0; j--) {
grid[j][i] = getTileAt(i,j-1);
grid[j-1][i] = null;
}
}
break;
}
x++;
}
}
Right now, I'm using keys to move the block:
public void keyPressed(KeyEvent e) {
int keyCode = e.getKeyCode();
if(keyCode == KeyEvent.VK_DOWN) {
activetile.setLocation(activetile.getX(), activetile.getY()+1);
System.out.println("coordinates: " + activetile.getX() + ", " + activetile.getY());
collisionCheck(activetile.getX(),activetile.getY());
checkBottomFull(0,4);
repaint();
}
}
There's two issues I'm having:
1) In the picture you'll notice I've dropped the block all the way to the floor... and the row cleared. After it's cleared, it will generate a block to the top left (x=0, y=1) which I have no control over.
2) On the floor there seems to be a red line... which I'm assuming is a row of blocks hidden by the JFrame... I'm not sure why that's there.
FYI: If you're wondering why grid[j][i] has the rows and columns flipped (aka, why it's not grid[i][j]) is because I instantiated it as grid = new Tile[height][width];
Any thoughts?
Thanks!
It is hard to say what is wrong without actually debugging your app.
But maybe try this one:
public void checkBottomFull(int x, int y) {
while (getTileAt(x,y) != null) {
say("(" + x + ", " + y +")");
if (x == 3) {
say("row is full");
//replace full row with tiles from above
for (int i = 0; i < 4; i++) {
for (int j = 4; j >= 0; j--) {
grid[j][i] = getTileAt(i,j-1);
grid[j-1][i] = null;
}
}
break;
}
x++;
}
}
You have 5 rows (indexed from 0 to 4) and 4 columns (indexed from 0 to 3).
What values of height and width do you pass to:
grid = new Tile[height][width];
Because from what I see you should do something like that:
grid = new Tile[5][4];
Bah,
Turns out in the key event, I needed to check if the bottom was full before checking if there is a collision.
I guess what was happening is, when I was checking collisionCheck(activetile.getX(),activetile.getY()); before checkBottomFull(0,4);, when the bottom was full, it would clear the row and set the current row equal to the row above it: grid[j][i] = getTileAt(i,j-1);, the problem was that collisionCheck was generating a new piece and the that newly generated piece was getting cleared and replaced by checkBottomFull.
Putting the collision check after the checkBottomFull ensures that the newly generated piece won't be replaced if bottom is full.

Categories

Resources