Click here to Skip to main content
15,887,027 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
I built a virtual aquarium. The problem on the one side is, that my moveFishes() method is really complex structured to the point, where I personally don't know how to structure it into different methods, while justifying, the program is still working. I'm asking if someone is able to structure my class and organize it into more simple methods.
On the other hand the collisions of fish are not properly working, and I cant figure out how to?

```
import java.util.Random;

public class Aquarium {

    public int depth;
    public int width;
    public Fish[][] fishes;

    public Aquarium(int depth, int width) {
        this.depth = depth;
        this.width = width;
        this.fishes = new Fish[depth][width];
    }

    public void printAquarium() {
        System.out.println();

        for (int i = 0; i < this.depth; i++) {
            System.out.print("|");

            for (int j = 0; j < this.width; j++) {
                if (fishes[i][j] != null) {
                    System.out.print(fishes[i][j].getAppearance());
                    j += fishes[i][j].getAppearance().length() - 1;
                } else {
                    System.out.print(" ");
                }
            }
            System.out.println("|");
        }

        System.out.print("+");
        for (int i = 0; i < this.width; i++) {
            System.out.print("-");
        }
        System.out.println("+");
        System.out.println();
    }

    public void setFish(int row, int column, Fish fish) {
        if (row >= 0 && row < depth && column >= 0 && column < width) {
            fishes[row][column] = fish;
        }
    }

    public void moveFishes() {
        for (int i = 0; i < this.depth; i++) {
            for (int j = 0; j < this.width - 1; j++) {
                if (fishes[i][j] != null && fishes[i][j + 1] != null) {
                    Fish currentFish = fishes[i][j];
                    Fish nextFish = fishes[i][j + 1];

                    if (currentFish.getDirection() && !nextFish.getDirection()) {
                        if (j + currentFish.getAppearance().length() > j + 1) {
                            handleCollision(i, j);
                        }
                    } else if (!currentFish.getDirection() && nextFish.getDirection()) {
                        if (j + 1 + nextFish.getAppearance().length() > j) {
                            handleCollision(i, j);
                        }
                    }
                }
            }
        }

        for (int i = 0; i < this.depth; i++) {
            for (int j = 0; j < this.width; j++) {
                if (fishes[i][j] != null) {
                    Fish currentFish = fishes[i][j];
                    boolean direction = currentFish.getDirection();

                    if (!direction) {
                        if (j + 1 < this.width) {
                            if (fishes[i][j + 1] == null) {
                                fishes[i][j + 1] = currentFish;
                                fishes[i][j] = null;
                                j++;
                                if (j == this.width - currentFish.getAppearance().length()) {
                                    currentFish.turnFish();
                                    currentFish.setDirection(!direction);
                                }
                            }
                        }
                    } else {
                        if (j - 1 >= 0) {
                            if (fishes[i][j - 1] == null) {
                                fishes[i][j - 1] = currentFish;
                                fishes[i][j] = null;
                                j--;
                                if (j == 0) {
                                    currentFish.turnFish();
                                    currentFish.setDirection(!direction);
                                }
                            }
                            changeDepth(currentFish, i, j);
                        }
                    }
                }
            }
        }
    }

    private void handleCollision(int i, int j) {
        Fish currentFish = fishes[i][j];
        Fish nextFish = fishes[i][j + 1];

        int currentFishLength = currentFish.getAppearance().length();
        int nextFishLength = nextFish.getAppearance().length();

        if (j + currentFishLength > j + 1 && j + 1 + nextFishLength > j) {
            if (currentFish.getDirection()) {
                fishes[i][j + 1] = currentFish;
                fishes[i][j] = nextFish;
            } else {
                fishes[i][j] = nextFish;
                fishes[i][j + 1] = currentFish;
            }
        }
    }

    private void changeDepth(Fish currentFish, int i, int j) {
        Random random = new Random();

        if (currentFish instanceof Fish.Shark && random.nextInt(4) == 0) {
            int newDepth = i + (random.nextBoolean() ? 1 : -1);
            if (newDepth >= 0 && newDepth < this.depth) {
                fishes[i][j] = null;
                fishes[newDepth][j] = currentFish;
            }
        } else if (currentFish instanceof Fish.PufferFish && random.nextInt(10) == 0) {
            int newDepth = i + (random.nextBoolean() ? 1 : -1);
            if (newDepth >= 0 && newDepth < this.depth) {
                fishes[i][j] = null;
                fishes[newDepth][j] = currentFish;
            }
        } else if (currentFish instanceof Fish.Swordfish && random.nextInt(5) == 0) {
            int newDepth = i + (random.nextBoolean() ? 1 : -1);
            if (newDepth >= 0 && newDepth < this.depth) {
                fishes[i][j] = null;
                fishes[newDepth][j] = currentFish;
            }
        }
    }

    public static void main(String[] args) {
        Aquarium a = new Aquarium(8, 30);

        Fish one = new Fish.Swordfish();
        Fish two = new Fish.Shark();
        Fish three = new Fish.PufferFish();
        Fish four = new Fish.NormalFish();

        a.setFish(2, 8, one);
        a.setFish(3, 3, two);
        a.setFish(5, 20, three);
        a.setFish(5, 8, four);

        for (int i = 0; i < 100; i++) {
            a.moveFishes();
            a.printAquarium();

            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

```

```
public class Fish {
    public String appearance;
    public boolean direction; // Direction of the fish (true: right, false: left)

    public Fish(String appearance, boolean direction) {
        this.appearance = appearance;
        this.direction = direction;
    }

    public String getAppearance() {
        return appearance;
    }

    public void setAppearance(String appearance) {
        this.appearance = appearance;
    }

    public void turnFish() {
        String newAppearance = "";
        for (int i = this.appearance.length() - 1; i >= 0; i--) {
            if (i >= 0 && i < this.appearance.length()) {
                char currentChar = this.appearance.charAt(i);
                if (currentChar == '>') {
                    newAppearance += '<';
                } else if (currentChar == '<') {
                    newAppearance += '>';
                } else if (currentChar == ')') {
                    newAppearance += '(';
                } else if (currentChar == '(') {
                    newAppearance += ')';
                } else {
                    newAppearance += currentChar;
                }
            }
        }
        this.appearance = newAppearance;
    }

    public boolean getDirection() {
        return direction;
    }

    public void setDirection(boolean direction) {
        this.direction = direction;
    }

    public static class NormalFish extends Fish {
        public NormalFish() {
            super("<><", true);
        }
    }

    public static class Shark extends Fish {
        public Shark() {
            super("<///====><", true);
        }
    }

    public static class PufferFish extends Fish {
        public PufferFish() {
            super("<()><", true);
        }
    }

    public static class Swordfish extends Fish {
        public Swordfish() {
            super("-<><", true);
        }
    }
}
```

<pre lang="Java"><pre lang="Java">


What I have tried:

I tried making a moveLeft and right method but they didn't work. Also I wanted to make a handleCollision method, but that didn't work either
Posted
Comments
[no name] 22-Dec-23 12:44pm    
The whole approach seems wrong. It's not "object oriented". "Location" should be properties of the fish. Fish are just "children" (collection) of the aquarium; not a multi-dimensional array.
0x01AA 23-Dec-23 9:28am    
In my opinion, this would fit as a reasonable answer.

1 solution

I hope this message helps you to continue. Before I tackle the moveFishes method, as well as some of the other methods (changeDirection, turnFish, etc), I think we should take a look at how we store all of the fish themselves:

Your fish are contained in a Fish[][], which is intuitive.

For this problem, we don’t have to use Fish[][]; for example, you might want to use a Set<fish>, because you might have a bunch of nulls.

Regardless, the best way to detect collisions, might be to use a SpacePartitioningTree — butttt
Your program is really simple, and it’s nice to keep everything simple.

I don’t always comment code when I should, but it is important to identify how you would like to check for collision.

——

Here are some example programs that might work:

public Fish( String appearance, direction ) { … } // direction could be a boolean in this case, or an enum would be easy

// Ie.
public enum Direction { LEFT, RIGHT, DOWN, UP … };

If you use a Fish[][] tank:
boolean collision ( Fish a, Fish b ) {
// return if indices match
}

Important note now: it is going to be important for each Fish object to track their position, for either system: Fish[][] or Set<fish>.

Back to our Fish constructor:

public Fish(…) {

int position_x = x;
int position_y = y;
}

To detect collision, you could do nested loops (which is easier to explain than the faster example):

for ( Fish fish1 : tank )
for ( Fish fish2 : tank )
if ( fish1 != fish2 )
return fish1.x == fish2.x && fish1.y == fish2.y; // returns true iff fish collide (have the same position)

This has a time complexity of O(n^2), a better solution is to use a SpacePartioningTree (specifically a QuadTree):
QuadTree<fish> QT
for ( Fish fish : tank )
QT.put( fish, fish.x, fish.y ) // at a position in the tree x,y, add the fish object

In the put method of that data structure, you could throw an error if the fish collide, or add an event handler.

This optimization is worth looking into, don’t just take my word for it, it’ll teach you a faster solution, that should work dynamically.

I’m gonna leave you with that information to start. To help answer your question about how you could reformat your code:
1) you gotta start adding some comments
2) you can compare your Strings directly, or, if they have more complicated inner logic, try looking at regular-expressions to see if there are any patterns that match in the strings.

Regexes are super helpful to understand, if you like working with Strings. If you don’t like working with Strings, it is hard to motivate reasons for learning it: regular expressions are intimidating, but not as difficult as they look.

- Cheers

I hope the project goes well
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900