0

This is for a personal project, I am trying to create a survival-like simulation using dinosaurs as agents.

The main part of the simulation is a do:while loop, and inside that do:while loop is 3 for:each loops (not nested) that run through three different ArrayLists. Each ArrayList is an array of objects, that each do different things.

Dinosaurs move around the field and can eat other Dinosaur objects, Grass objects, or Water objects. Neither Grass objects nor Water objects disappear after being eaten, however Dinosaur objects are removed from the dinosaurs ArrayList if they are eaten. Here's my relevant code:

for (Grass grass : grasses) {
    System.out.println(grass);
}

//simulation loop
do {
    for (Grass grass : grasses) {
        grass.timeToGrow();
    }
    for (Water water : waters) {

    }
    for (Dinosaur dinosaur : dinosaurs) {
        if(simulationLength % 3 == 0) { //dinosaurs lose 1 health and food every 3 turns
            dinosaur.addFood(-1);
            dinosaur.addWater(-1);
        }
        dinosaur.loseHealth();
        dinosaur.move(dinosaurs, grasses, waters);
        dinosaurs.add(dinosaur.timeToReproduce());
    }
    System.out.println("There are " + dinosaurs.size() + " dinosaurs left.");
    simulationLength -= 1;
    simulationTime += 1;
    //TODO update GUI
} while (simulationLength > 0);

System.out.println("¡THE SIMULATION IS DONE!");

dinosaur.move() moves each dinosaur in the ArrayList of dinosaurs. If a dinosaur is a carnivore and lands on another dinosaur it eats it, and the eaten dinosaur is removed from the list. dinosaur.timeToReproduce() returns a Dinosaur object if the dinosaur is supposed to use food and make another Dinosaur (that is added to the list of Dinosaurs) and null if not.

public void move(ArrayList<Dinosaur> dinosaurs, ArrayList<Grass> grasses, ArrayList<Water> waters) {
    Positioned food = getFoodSource(dinosaurs, grasses, waters);
    try { //to find food
        if(distanceTo(food) <= getSpeed()) {    //can move to food in one turn
            moveInRange(dinosaurs, grasses, waters);
        } else {                                //food is out of reach
            moveOutRange(dinosaurs, grasses, waters);
        }
    } catch (NullPointerException e) { //didn't find any food :(
        //TODO make the dino search for alternate food source
        //TODO make the dino wander if truly no food

        //not yet moving
        setxLoc(getxLoc());
        setyLoc(getyLoc());
    }
}

public void moveInRange(ArrayList<Dinosaur> dinosaurs, ArrayList<Grass> grasses, ArrayList<Water> waters) {
    Positioned food = getFoodSource(dinosaurs, grasses, waters);      //searching out target...

    int xLocFood = food.getxLoc();
    int yLocFood = food.getyLoc();

    this.setxLoc(xLocFood);
    this.setyLoc(yLocFood);

    switch (food.getName()) {
        case "grass":
            //grass just got eaten. it now has to regrow
            System.out.println(this + " just ate " + food + "!");
            grasses.get(grasses.indexOf(food)).setGrowthStage(1);
            this.addHealth(4);
            this.addFood(4);
            break;
        case "water":
            //you gots to do nothing. water doesn't go away
            System.out.println(this + " just drank " + food + "!");
            this.addHealth(2);
            this.addWater(4);
            break;
        case "dinosaur":
            //remove the dinosaur you just ate
            System.out.println(this + " just tried to eat " + food + "!");
            battle(dinosaurs.get(dinosaurs.indexOf(food)), dinosaurs);
            break;
    }
}

public void moveOutRange(ArrayList<Dinosaur> dinosaurs, ArrayList<Grass> grasses, ArrayList<Water> waters) {
    Positioned food = getFoodSource(dinosaurs, grasses, waters);      //searching out target...

    //if there is not a valid food source found then the next 2 lines will throw a NullPointerException
    int xLocFood = food.getxLoc();
    int yLocFood = food.getyLoc();

    int newXLoc;
    int newYLoc;
    double dx = xLocFood - getxLoc();   //total x distance to food
    double dy = yLocFood - getyLoc();   //total y distance to food
    double theta = Math.atan(dy / dx);      //θ = arctan(dy/dx)

    //rounding for accuracy
    newXLoc = (int) Math.round(getSpeed() * Math.cos(theta));   //x=speed*cos(θ)
    newYLoc = (int) Math.round(getSpeed() * Math.sin(theta));   //y=speed*sin(θ)

    setxLoc(getxLoc() + newXLoc);                           //newX = x+moveX
    setyLoc(getyLoc() + newYLoc);                           //newY = y+moveY
}

public void battle(Dinosaur dino, ArrayList<Dinosaur> dinosaurs) {
    //attack vs defense
    int dH = this.getAttack() - dino.getDefense();
    if(dH > 0) {        //dinosaur's attack is greater than the other guy's defense
        System.out.println("\t" + dino + " just lost " + dH + " health!");
        dino.addHealth(-dH);
        this.addFood(dino.curFood / 2);
        if(dino.getHealth() <= 0) {
            System.out.println("\t" + dino + " was just eaten!");
            for (int i = 0; i < dinosaurs.size(); i++) {
                if(dinosaurs.get(i).equals(dino)) {
                    dinosaurs.remove(i);
                }
            }
        }
    } else if(dH < 0) {   //defender has the big defense
        System.out.println("\t" + this + " just lost " + dH + " health!");
        this.addHealth(dH);
        badDinos.add(dino);
    }
}

I have seen some stuff about Iterators, is that what I should use? If so, how do they work? Should I just create a new ArrayList in move()/battle() and timeToReproduce() and then remove stuff after finishing the dinosaurs loop? If so, how do I make sure that dinosaurs that were supposed to be eaten actually are?

I will keep updating with details as people ask for them.

Neuron
  • 5,141
  • 5
  • 38
  • 59
elkshadow5
  • 369
  • 2
  • 4
  • 17
  • Iterator solve the remove issue, but for adding I'm not sure – Marcos Vasconcelos Apr 25 '18 at 20:42
  • Depends on what you want to achieve. I.e. what should happen when your code adds a dinosaur to the list of dinosaurs it's currently working on? Should that be part of the iteration or not? If modifications are meant to be only in effect the next round, then iterate on a copy of the current state – zapl Apr 25 '18 at 20:44
  • The solution I see here is you need to think for thread safety. I would recommend you to use a Concurrent Collection Object eg: ConcurrentHashMap because this will save you from the exception you are getting. You will have to pay for performance but the solution remains feasible. – Nesan Mano Apr 25 '18 at 20:51
  • Another solution would be to use an array([]) if you don,t have too many dinosaurs. – Nesan Mano Apr 25 '18 at 20:53
  • Note that even if this worked, `dinosaurs.add(dinosaur.timeToReproduce());` adds another element to `dinosaurs` every time so you'd be iterating forever (or until it hits a null and throws an NPE). You need to check if the return value of `timeToReproduce()` is null before adding it, otherwise you're just adding nulls to the list. – Sean Van Gorder Apr 25 '18 at 21:08
  • @MarcosVasconcelos can you not add items to an Iterator? @zapl I realize now that it would probably be best that any dinosaurs that are added should do so after the original dinosaurs have moved, which solves that problem- add to an ArrayList `dinosaurstoAdd` for example, then add them after the loop is complete. @NesanMano I would prefer not to use the standard array as ArrayLists have a few more options and a bit more flexibility. @SeanVanGorder thank you for helping me realize that. Yes, I do not want to add nulls to the list XD – elkshadow5 Apr 28 '18 at 04:32

0 Answers0