incrementing an object in a 2d array - java

Good day, so I intend for my code to loop through my array and increment the row index of object by 1 position. I used timer task because I want the object to move forward after certain amount of time. This is the code I have tried. I have looked but I have struggled to find solution relevant to my problem. Would appreciate the help.
class cat_function extends TimerTask {
public void run() {
synchronized (game.board) {
for (int i = 0; i < game.board.length; i++) {
for (int k = 0; k < game.board[0].length; k++) {
if (game.board[i][k] instanceof cat) {
cat garfield = new cat(0, 0);
game.board[i][k] = garfield;
game.board[i][k + 1] = garfield;
}
}
}
}
}
}

Assuming:
game.board is defined as a Cat[][]
an empty cell's value is null
Then all you have to do is
if (game.board[i][k] instanceof cat) {
game.board[i][k + 1] = game.board[i][k]; // Put cat in new location
game.board[i][k] = null; // Remove cat from previous location
}
However, this code still has two problems
What do you do when you reach the edge of the board. You'll have to add logic to make it do something different so you don't fall of the edge.
There's no need to scan the entire game board every time just to find the Cat. Keep the cat's location (indexes) separately so you always know where it is and don't have to look for it.
If there can be more than one cat on the board you will also need logic to decide what happens if two cats "collide" when moving (i.e. you try to move a cat into a cell that already contains a cat).
Solving those problems is left as an exercise for you.

Related

Simple flood fill method causes StackOverFlow error

My flood fill method:
public void fillNeighbours(int x, int y) {
for(int i = -1; i < 2; i++) {
for(int j = -1; j < 2; j++) {
try {
visible[x+i][y+j] = true;
if(num[x+i][y+j] == 0) {
fillNeighbours(x+i, y+j);
}
} catch (ArrayIndexOutOfBoundsException ignored) {}
}
}
}
That catch (ArrayIndexOutOfBoundsException ignored) {} is there for avoiding x and/or y position from going outside of the array. Array size is 30 by 30. I'm making minesweeper like game. So you may know why I need this method and how it should work. If u don't know what minesweeper is then here is quick video about that game: Introduction to minesweeper
The code revisits fields which are set to visible already.
Try something like
if(!visible[x+i][y+j]){
visible[x+i][y+j] = true;
if(num[x+i][y+j] == 0) {
fillNeighbours(x+i, y+j);
}
}
It looks like you're recursively calling fillNeighbours without any break out clause (base case) so the calls fill the stack.
From
Wikistack
The tree laws of recursion are
A recursive algorithm must have a base case.
A recursive algorithm
must change its state and move toward the base case.
A recursive
algorithm must call itself, recursively.
Once fillNeighbours finds a cell and calls itself, the next loop will always call another when i and j are equal to zero. So it will never exit, and crash once the stack is full.
Aside from that, it will produce a very deep tree as it is not keeping track of which cells have been recursed, and will call fillNeighbours on the same cell multiple times.

Appium: How to iterate over a listview of unknown length?

I have a list view with a hierarchy I theoretically have no knowledge of. I am attempting to accept a String array and create MobileElements for each string in it, but due to the way I've automated (PageFactory) defining my elements via annotations, they cannot use variables. I also don't know that it's valid or proper to define my annotations inside a method.
The code I've written, which obviously does not compile follows:
public void selectLocation(String[] location) {
List<MobileElement> locationsList = new ArrayList<>();
for(int i = 0; i < location.length; i++) {
#iOSFindBy(accessibility = location[i])
#AndroidFindBy(xpath = "//android.widget.TextView[#text='" + location[i] + "']")
locationsList.add(i);
}
for (int i = 0; i < location.length; i++) {
locationsList.get(i).click();
}
}
I'm assuming the proper way to do this is wholly different from the way I've implemented.
My list hierarchy is similar to the following; my end point could vary depending on the branch I go down:
Continent 1
City 1
Room 1
Room 2
City 2
Building 1
Room 1
Room 2
Building 2
Room 1
Room 2
I now look for a matching element. If I don't find it, I swipe further into the list. If the element doesn't exist I obviously run into problems, but not really an issue in my case since that’d be a failing test.
while (!driver.findElementById(currentLocation).isDisplayed()) {
driver.swipe(startX, startY, startX, endY, 100);
}
driver.findElementById(currentLocation).click();
Yes, I also realize .swipe() is deprecated, but it still works for me and I'd rather not rewrite all my code with TouchActions until necessary.
I ended up using the "FindsBys" functions to create an array of all matching elements. I then loop through those elements looking for a match to one of my strings.
#AndroidFindBys({#AndroidFindBy(xpath = "//android.widget.TextView")})
#iOSFindBys({#iOSFindBy(xpath = "//XCUIElementTypeStaticText")})
private List<MobileElement> locationsList;
...
public void selectLocation(String[] location)
{
for(int i = 0; i < locationsList.size(); i++)
for(int p = 0; p < location.length; p++) {
if (locationsList.get(i).getText().equals(location[p])) {
locationsList.get(i).click();
}
}
}
It's not foolproof (if you have duplicate strings at different levels of your hierarchy you may run into issues), but it works for my use-case and should be able to guide anyone looking for a stronger solution.
You can just loop over the elements themselves.
....
for(MobileElement location: locationsList) {
for(int p = 0; p < location.length; p++) {
if (location.getText().equals(location[p])) {
location.click();
}
}
}

Java: Optimizing algorithm in game

I'm creating a game (Java) with scene2d.
I wrote function for collision detection but I think it's bad function. It looks bad.
How can I optimize it? Make faster and more beautiful.
private void deleteEnemies()
{
for(int i = 0; i < getActors().size - 1; i++)
{
if(getActors().get(i) != null && getActors().get(i) instanceof Enemy)
{
////////////////
for (int j = 0; j < getActors().size - 1; j++)
{
if(getActors().get(j) != null && getActors().get(j) instanceof Ball)
{
if (actorsIntersecting(getActors().get(i), getActors().get(j)))
{
getActors().get(i).remove();
getActors().get(j).remove();
}
}
}
//////////////
}
}
}
Put getActors().get(i) in a variable, dont call it twice in the outer if
Same for getActors().get(j) in the inner if
use these variable in the most inner if's condition and body
save the size in a variable because now the .size function is being called on every iteration when the for condition is checked
You shouldn't use a size that can dynamically change during the loop for the loop condition (because you are removing items as you go) which brings us back to #4.
Other than that its pretty much ok coding style perspective and I doubt you can make it more efficient than with what I told you (Other than using threads)
Since you will do this frequently, consider storing the Enemies and Balls in their own structures (List or Set or whatever works). That prevents you from looping through actors you don't need, and avoids the instanceof checks.
Well, my first idea was to check only "nearest" enemies and not all of them. Somehow try to decrease size of that list.
2. Second one - please check your and conditions in and one by one - now you are checking 2 conditions always. Try to put "heavier" if later, for example:
from:
if(getActors().get(i) != null && getActors().get(i) instanceof Enemy)
to:
if(getActors().get(i) != null) {
if(getActors().get(i) instanceof Enemy) {
.....
}
}
3. call your getActors().get(i) one time - save to variable.
4. I'm thinking why is it necessary to check if an actor is null, maybe just remove nulls from list or keep uninitialized actors on another list. Also try this with Balls and Enemies, please don't keep every actor on a single list.
I would rewrite the models a bit, so they can test the intersection itself and then do the delete like that (probably it can still be improved)
private void deleteEnemies () {
List<Actor> actors = getActors();
List<Actor> toRemove = new ArrayList<Actor>();
int actorsSize = actors.size();
Actor first = null, second = null;
for(int i = 0; i < actorsSize; ++i) {
first = actors.get(i);
for(int j = 0; j < actorsSize; ++j) {
if(i == j) continue;
second = actors.get(j);
if(first.intersects(second)) {
toRemove.add(first);
toRemove.add(second);
}
}
}
actors.removeAll(toRemove);
}
Don't use size(), define a variable
Try not to cast. Try not to uae instanceof.
Maybe, sort lists by zsort or the like so u can, sometimes, start and or stop the loops sooner??
Adding to the (very good) suggestions of the other participant: cache the enemies and projectiles in separate structures, so you don't have to check what they are at all.
Use the time vs space trade-off as much as you can: the standard approach, as hinted by Tomek, in this kind of situations is to reduce the number of checks (=iterations) by pruning the enemies and projectiles that cannot possibly collide within the current frame (they are way to far).
Anyway, a word of advice: go on with the game, complete as much as you can so that it will run correctly (if slowly), and only then go for the optimization.
That because
by optimizing preemptively in this way you will never finish it
you don't know how the final game really will be, perhaps: maybe after finishing 90% of it, you will see some easy chances for optimization.
As others have said, the real improvement to speed would be two collections, one with balls and the other with enemies. As for making it look nicer, you could something like this:
for (Actor enemy : getActors()) {
if (enemy != null && enemy instanceof Enemy) {
for (Actor ball : getActors()) {
if (ball != null && ball instanceof Ball && actorsIntersecting(enemy, ball)) {
ball.remove();
enemy.remove();
}
}
}
}

A collision check method works on a mac, but not on PC

So I am stumped. Here is my collision check method`
public void checkCollision ()
{
for (int i = 0; i < bullets.size()-1; i ++)
{
for (int j = 0; j < enemiesLaunched.size()-1; j++)
{
Rectangle temp = enemiesLaunched.get(j).getRectangle();
Rectangle temp2 = bullets.get(i).getRectangle();
`
if (temp2.intersects (temp))
{
String str = bullets.get(i).getPath();
// since the bullets are selective, the following code is to check
// if the right bullets hit the right germs
if (str.equals("oil gland.png")) // bullet is from oil gland
{
if (enemiesLaunched.get(j).getInfo().equals("highAcid"))
{
enemiesLaunched.get(j).setVisible(false);
bullets.remove(i);
}
}
else if (str.equals ("sweat gland.png"))
{
if (enemiesLaunched.get(j).getInfo().equals("lysozome"))
{
enemiesLaunched.get(j).setVisible(false);
bullets.remove(i);
}
}
else
{
if (enemiesLaunched.get(j).getInfo().equals("mucus"))
{
enemiesLaunched.get(j).setVisible(false);
bullets.remove(i);
}
}
`
On my mac, it works exactly how I intended. However, on my PC, it does not. To make matters more baffling, I have implemented the same logic on games further along in the game, and it works just fine on both the mac and pc, any help would be greatly appreciated!
How are you doing your time delta, and what is the velocity on the two objects? If your time delta is sufficiently large enough, you might not detect the collision as the two objects could have pass right through each other between checks. Have a look here for an explaination.
What tears attention is size()-1 - sure? But bullets.remove(i); certainly should be followed by --i; as otherwise the for-incrementing would skip the next bullet.
Optimized it would be by keeping get(i) and get(j) in their own variables.
I'd rather use for-loops like this if possible to ensure I don't have some wrong indexes due to typos or something:
List<Enemy> enemies = new ArrayList<Enemy>;
for (Enemy enemy : enemies) {
...
}
For example with this loop:
for (int i = 0; i < enemies.size()-1; ++i)
you will always leave the last "enemy" untouched.
And then, to be sure I'm not screwing up my Lists and iterations I would keep references to objects that need to be removed and would remove them afterwards, because I'm not sure what happens when removeing items from a collection while iterating over the same collection. The behaviour might be collectiontype and implementation (of the collection) specific.

Snake game, How to make a snake move?

I am writing a snake game, specifically, is a centipede game. It needs me to draw a snake and that snake will automatically move one line by one line.
I did draw a snake, and it can move from left side to right side. However, the problem is:
I can't make the snake changes line, if it finish the first line, I need it changes to the second line and which starts from the right side.
My code is like this:
private void move()
{
myCentipedes[0] =
new Centipede(Settings.centipedeStartSize, Settings.RIGHT,
Settings.DOWN);
myCentipedes[0].segments = new Point[Settings.centipedeStartSize];
myCentipedes[0].segments[0] = new Point(0, 0);
boolean dr = true;
if (dr == true) {
if (myCentipedes[0].segments[0].x < 30) {
System.out.println(myCentipedes[0].segments[0].x +
" " +
myCentipedes[0].segments[0].y);
myCentipedes[0].segments[0] = new Point(x, 0);
for (int i = 1; i < 10; i++) {
myCentipedes[0].segments[i] =
new Point(myCentipedes[0].segments[i - 1].x - 1,
myCentipedes[0].segments[i - 1].y);
}
x++;
}
}
if (myCentipedes[0].segments[0].x == 29) {
x = 29;
dr = false;
}
if (dr == false) {
if (myCentipedes[0].segments[0].x > 0) {
myCentipedes[0].segments[0] = new Point(x, 1);
for (int i = 1; i < 10; i++) {
myCentipedes[0].segments[i] =
new Point(myCentipedes[0].segments[i - 1].x + 1, 1);
}
x--;
}
}
}
It appears to me that you re-create your entire centipede on every single move:
private void move()
{
myCentipedes[0] =
new Centipede(Settings.centipedeStartSize, Settings.RIGHT,
Settings.DOWN);
Is re-creating the centipede every move() intentional? Or should move() run the centipede entirely down the board, from start to finish? (If so, you'll need to add some looping to this method.)
I assume the myCentipedes[0] is simply a placeholder for future extensions, involving two or more centipedes on the board simultaneously. This sort of over-generic programming can sometimes make the code more difficult to read and write while initially programming, and almost certainly doesn't help matters. You can always re-factor a move() method that works on one centipede to a move(int centipede) method that works on a specific centipede and a move() method that calls move(int) for every centipede on the board. Or maybe you'll find it easier to place the movement code into the Centipede class, and need to remove the array indexes then and use class member storage instead.
boolean dr = true;
if (dr == true) {
dr will always equal true at this point. You might as well remove the variable and the test.
for (int i = 1; i < 10; i++) {
myCentipedes[0].segments[i] =
new Point(myCentipedes[0].segments[i - 1].x - 1,
myCentipedes[0].segments[i - 1].y);
}
Since you're counting up, you'll actually copy the value from segment[0] through to all elements in the array, one element at a time. Can't you just assign the Point objects new array indexes? Starting from i=centipede.segments.length and counting down, it'll look more like this:
for (int i=myCentipede[0].segments.length; i > 0; i--) {
myCentipede[0].segments[i] = myCentipede[0].segments[i-1];
}
myCentipede[0].segments[0] = new Point(...,...);
Some of your tests can be simplified:
if (myCentipedes[0].segments[0].x == 29) {
x = 29;
dr = false;
}
if (dr == false) {
if (myCentipedes[0].segments[0].x > 0) {
If dr == false at this point, you might as well have written it like this instead:
if (myCentipedes[0].segments[0].x == 29) {
x = 29;
if (myCentipedes[0].segments[0].x > 0) {
But then the second if is obviously not needed -- after all, 29 > 0.
While you're here, clean up all those hard-coded 10 with either a constant (Settings.centipedeStartSize) or find the actual length of the centipede (myCentipedes[0].segments.length).
Now that I've critiqued your current approach, I'd like to suggest a different tack:
Take a step back and break your problem down into smaller methods.
You've embedded two for loops that move the centipede one segment at a time by assigning to segment[i] the values from segment[i-1]. Instead of duplicating the code, write a new method with the body of the for loop to move the centipede forward. Make it take a Point object for the new first element each trip through the function. (Don't forget to make it count down rather than up.)
Once you've broken apart the for loops, I think it will be easier to make whatever changes are necessary for traveling left-to-right and right-to-left. You will probably want to write it with nested for loops -- one to control the vertical dimension, and within it, perhaps one or two new for loops to control the horizontal dimension. Make these loops work with a simple Centipede c, rather than the complicated expression you've currently got.
Breaking apart the larger function into smaller function will give you a better opportunity to test your functions in isolation -- test movement manually, with simple test methods like this:
move_forward(Centipede c, Point p) {
/* code to move forward one space to occupy `p` */
}
test_right() {
Centipede c = new Centipede(/* ... */);
move_forward(c, new Point(0,0));
move_forward(c, new Point(1,0));
move_forward(c, new Point(2,0));
move_forward(c, new Point(3,0));
move_forward(c, new Point(4,0));
move_forward(c, new Point(5,0));
/* ... */
}
Take it slow, test every method as you write them, and I think you'll find this is an easier problem than it currently looks.

Categories

Resources