This site requires JavaScript, please enable it in your browser!
Greenfoot back
nexus
nexus wrote ...

2012/5/17

How to birth an death

nexus nexus

2012/5/17

#
edit: sorry for the incorrect title Hi everyone, I'm relatively new to java so I need some help by coding my first scenario. The main part is based on the "Boids" (simulation of a flock of birds) but I'm trying to improve this code in some ways. Right now I'm working on implementing birth and death of the birds. I'd like to have one new bird (birth) on every ten birds (so a reproduction rate of 1 "child" per 10 birds) and a death rate of five percent (one death per 20 birds). My idea was to get the whole amount of birds with getObjects(bird.class) and then multiply this amount with 0.1 (for birth) and 0.05 (for death). At this point we would have the number of how many birds will be added to the world and how many will be remove. Now I'd thought each of these numbers could be put into a seperate while-loop like this:
int i = 0
while (i < amount of biths)
{
addObject(new bird(), Greenfoot.getRandomNumber(900), Greenfoot.getRandomNumber(700));
i = i + 1
}
The same with the number of dead birds with removeObject(bird). Since that would be just the basic process, I have no idea how to really code this...Help would be appreciated :)
danpost danpost

2012/5/17

#
You could just combine the two by using
while (i < amount_of_births - amount_of_deaths)
Equivalent, but not exactly the same (as removing and adding cancel each other out, here). But, if you want to keep them seperate, then use this:
for (int i = 0; i < number_of_deaths; i++)
{
    removeObject(getObjects(bird.class).get(0));
}
I think, though, that you are going to need some type of population control (or you will run out of memory eventually).
nexus nexus

2012/5/20

#
Thanks for your reply, but the problem ist how to get the current amount of all boids. I've tried this, but it doesn't work:
private int killBoids(Class cls)
    {
        int allObjects = getWorld().getObjects(Boid.class);
        (getObjects.size*0.1) = currentAmount;
        for (int i = 0; i < currentAmount; i++)
        {
            int x = 500;
            int y = 200;
            addObject(new Boid(),x,y);
        }
    }
Greenfoot says "incompatible types" to "Boid.class" in get.Objects. After I received the amount of boids (which sadly doesn't work) I wanted to calculate the amount of how many new birds should be added (10 percent so *0.1) but it can't be compiled since List and int doesn't fit together... 2nd problem: If the "run" button is clicked, Greendfoot runs the act() method in an endless loop. What can I do to create a method which is called every lets say 20 rounds, so it should be executed every 20 times the act() method is called. Regards from Germany
danpost danpost

2012/5/20

#
Problem 1: you are getting a List of all boid objects in the world, but not returning the size of that list; you need to use 'getObjects(Boid.class).size()'. Problem 2: you will need to add a field to the world to hold the count of act cycles and in the 'killBoids' method, increment it, check it, and return early if not yet time to add more boids. Replace your 'killBoids' method with
private int timer = 0;

private void killBoids()
{
    timer++;
    if (timer < 20) return;
    timer = 0;
    int boidCount = getObjects(Boid.class).size();
    currentAmount = boidCount / 10;
    for (int i = 0; i < currentAmount; i++)
    {
        int x = 500;
        int y = 200;
        addObject(new Boid(),x,y);
    }
}
You should probably rename the method from 'killBoids' to 'addBoids', which is more appropriate. Also, 'currentAmount' is a bit vague; how about, instead, using 'boidsToAdd'. BTW, the code above is in your sub-class of World, I hope.
nexus nexus

2012/5/20

#
Thank you very much, but it says "cannot find symbol - variable boidsToAdd". Simple but cool idea to increase the timer everytime the addBoids() method is called since it is part of the act() method... didn't thought that way.
danpost wrote...
You should probably rename the method from 'killBoids' to 'addBoids', which is more appropriate. Also, 'currentAmount' is a bit vague; how about, instead, using 'boidsToAdd'.
You are absolutely right, changed the code :)
danpost danpost

2012/5/20

#
Lines 9 and 10 should be:
int boidsToAdd = boidCount / 10;
for (int i = 0; i < boidsToAdd; i++)
nexus nexus

2012/5/20

#
I've changed line 6 to
if (timer > 20) return;  
since nothing happened before. Now new boids are created but only at the start of the simulation, not at every 20 rounds (tried it with smaller numbers like 3 or 7, too). EDIT: interesting: if I change the counter-values to
       if (timer > 2) return;  
        timer = 0;  
        int boidCount = getObjects(Boid.class).size();  
        int boidesToAdd = boidCount / 2; 
12 boids are generated (at the beginning) but if I use
       if (timer > 10) return;  
        timer = 0;  
        int boidCount = getObjects(Boid.class).size();  
        int boidesToAdd = boidCount / 5; 
there are only five boids created.
danpost danpost

2012/5/20

#
Try this:
private int timer = 0;
private int carryoverBoids = 0;

private void killBoids()
{
    timer++;
    if (timer < 20) return;
    timer = 0;
    int boidCount = getObjects(Boid.class).size();
    int combinedBoids = carryoverBoids + boidCount;
    carryoverBoids = combinedBoids % 10;
    int boidesToAdd = combinedBoids / 10;
    for (int i = 0; i < boidsToAdd; i++)
    {
        int x = 500;
        int y = 200;
        addObject(new Boid(),x,y);
    }
}
Hopefully, you can start with just one Boid with this.
danpost danpost

2012/5/20

#
Give it time, though. It might start off a bit slow. I think you might have mis-counted the generated boids. You probably have multiple boids at (500, 200) on top of each other. Also, it has to be 'if (timer < "some number") return; or the timer will ALWAYS be reset to zero and it would be like you did not have the timer at all.
nexus nexus

2012/5/20

#
I'm sorry, but this doesn't work as well. I have given it enough time, set speed to max and let the simulation run for 30 seconds - nothing changed. Then I've tried to solve it with two methods, but that has not the desired effect neither.
    private int timer = 0;
    private boolean randomTimer()
    {
        timer ++;
        if (timer < 10) 
        {
            return false;
        }
        else
        {
            return true;
        }
    }
       
    private void addFishes()  
    {  
    if (randomTimer() == true);
    {
        int fishCount = getObjects(Fish.class).size();  
        int fishesToAdd = fishCount / 2;  
        for (int i = 0; i < fishesToAdd; i++)  
        {  
                int x = Greenfoot.getRandomNumber(900);  
                int y = Greenfoot.getRandomNumber(700);  
                addObject(new Fish(),x,y);  
        }  
    timer = 0;
    }  
  }
Don't be irritated by the fishes, that are my boids :) Unless randomTimer() should be false at the first round, the world is initialized with 150% percent of the original amount of fishes (normal 100% + fishCount / 2). By this time it seems to be an unsolvable problem but there must be a solution...
danpost danpost

2012/5/20

#
I put this in my Boid class
import greenfoot.*;

public class Boid extends Actor
{
    public Boid()
    {
        setRotation(Greenfoot.getRandomNumber(360));
    }
    
    public void act() 
    {
        move(5);
        if (Greenfoot.getRandomNumber(100) < 10) turn (10);
    }    
}
and this in the world class
import greenfoot.*;

public class Bworld extends World
{
    private static int wide = 600;
    private static int high = 400;
    private int timer = 0;
    private int carryoverBoids = 0;
    
    public Bworld()
    {    
        super(wide, high, 1);
        addObject(new Boid(), wide / 2, high / 2);
    }
    
    public void act()
    {
        addBoids();
    }

    private void addBoids()
    {
        timer++;
        if (timer < 20) return;
        timer = 0;
        int boidCount = getObjects(Boid.class).size();
        int combinedBoids = carryoverBoids + boidCount;
        carryoverBoids = combinedBoids % 10;
        int boidesToAdd = combinedBoids / 10;
        for (int i = 0; i < boidesToAdd; i++)
        {
            int x = Greenfoot.getRandomNumber(wide);
            int y = Greenfoot.getRandomNumber(high);
            addObject(new Boid(),x,y);
        }
    }
}
and it looked pretty good to me!
nexus nexus

2012/5/21

#
Tried this in a new scenario and you're absolutely right - it works! I've no idea why nothing happens in the other scenario :S
nexus nexus

2012/5/21

#
Hahaha found my mistake: I accidentally deleted the act() method so I put the method call for addBoids() right below addObject(new Boid).... Changed it and now it works fine! Last question, after that the scenario is completed: I want to set a maximum amount of boids. If this maximum is reached a random number of boids shall be removed. That's my code:
private void edgeOfPopulation()
    {
        int totalPopulation = getObjects(Boid.class).size();
        if (totalPopulation > 50)
        {
            for (int i = 0; i < Greenfoot.getRandomNumber(15); i++)
            {
                removeObject(Boid.class);
            }
        }
    }
Unfortunately it can't be compiled - whats wrong with that removeObject(Boid.class) ?! P.S. thank you very much for your help so far!
You need to login to post a reply.