Question

So i wrote a simulation of rabbits and wolves, and I have a single thread that in its run iterates for all animals in for loops - one for rabbits and one for wolves. So:

public void run(){
    while(rabbitNumber!=0){
                for(int i=0; i<rabbitsNumber; i++){ doRabbitMove();}
                for(int i=0; i<wolvesNumber; i++){ doWofMove();}
            }
    }

Now, I need a pause after each wolf and rabbit move - but not for a whole thread, just for that one i'th animal. I can't put just sleep after doWolfMove/doRabbitMove as it will stop the iteration on everything. Is there any way I can make it work? I don't want to use single thread for each animal.

Was it helpful?

Solution

I agree with @Groo. Implementing a shouldMoveXXX is a much better idea than needlessly messing with concurrency. You could still make this time based(as your comments make you seem like you want) like this:

// time between each move
final int SLEEP_TIME = 1000;

//each animal has this variable, it is the last time they moved
long lastMoveTime;

public boolean shouldMoveRabbit(){
    if(System.currentTimeMillis() >= lastMoveTime + SLEEP_TIME)
         return true;
    return false;
}
public void doMoveRabbit(){
    lastMoveTime = System.currentTimeMillis();
    // move stuff
}

OTHER TIPS

I am not totally clear about your needs but you could do it with just a few threads - perhaps even just one extra thread.

I would set up the processing requirements (all animals must move) into a DelayQueue and process the queue in a separate thread.

DelayQueue - An unbounded blocking queue of Delayed elements, in which an element can only be taken when its delay has expired.

Post each move of your animals into the queue with the delay you want. Have one separate thread take each event from the queue and perform it. The queue will perform the blocking and the scheduling for you - no need to sleep at all.

Whenever you process one animal move from the queue, re-post it back into the queue with your required delay.

If this is a game loop, then it might make more sense to go in this direction:

public void run() {

    while (rabbitsNumber > 0) {

        for (int i=0; i<rabbitsNumber; i++)
             if (shouldMoveRabbit(i)) doRabbitMove();

        for (int i=0; i<wolvesNumber; i++)
             if (shouldMoveWolf(i)) doWolfMove();

        renderScreen();    
    }
}

These shouldMoveXXX methods should simply return false for a certain animal index, at an appropriate time. And I presume this should be linked to the "turn" number, rather than actual time (which will depend on you rendering speed and other factors).

What you want to do is think in terms of frames. Update everything every frame (e.g 1/60th of a second) then sleep till the next frame (an animal doesn't have to do anything when its updated, its just given the opportunity to).

So say that one rabbit moves then needs to rest for 2 seconds before moving again. Each rabbit would have an instance variable of restTime which it would set to 2 seconds after making a move. Each frame it would reduce this variable by the frame time (1/60th of a second). When the variable is zero or less it moves again. This means that you can do it all one one thread and the animals movements are not dependant on each other (except for when you want them to be of course).

If you're animating this it's best to measure the actual frame time and use that rather than assuming you'll actually get exactly the 1/60th of a second you asked for.

An example might be as follows

public class Rabbit {
    private double timeBetweenMoves;
    private double sleepTime=0;
    private String name;

    public Rabbit(String name,double timeBetweenMoves) {
        this.name=name;
        this.timeBetweenMoves=timeBetweenMoves;
    }



    public void update(double timeSlice){
        sleepTime-=timeSlice;

        if (sleepTime<0){
            makeMove();
        }
    }

    private void makeMove(){
        sleepTime=timeBetweenMoves;

        //actually make the move

        System.out.println(name + " Moved");
    }


    public static void main(String[] args){

        double frameTime=1/60.0;

        List<Rabbit> rabbits=new ArrayList<>();

        rabbits.add(new Rabbit("Floppsy",2)); //moves every 2 seconds
        rabbits.add(new Rabbit("Hopper",5)); //moves every 5 seconds

        while(true){
            for(Rabbit rabbit:rabbits){
                rabbit.update(frameTime); //assumes frametime is actually what you asked for, can cause graphics to look stuttery
            }
            try {
                long milllisecondsToSleep=(long)(frameTime*1000);
                Thread.sleep(milllisecondsToSleep);
            } catch (InterruptedException ex) {
                Logger.getLogger(Rabbit.class.getName()).log(Level.SEVERE, null, ex);
            }
        }

    }

}

Here is a solution that doesn't require using Sleep() or threads, basically we will be doing a simulation, same logic is used in video game development.

public class Simulation 
{
    int clock;

    public static void simulate (Location r, Location w, int end_time)
    {
        clock = 0;

        Rabbit rabbit = new Rabbit (r);
        Wolf wolf = new Wolf (w);

        while (clock < end_time)
        {
            rabbit.update(clock, wolf.getLocation());
            wolf.update(clock, rabbit.getLocation());

            if(interlace(rabbit.getLocation(), wolf.getLocation()))
            {
                System.out.println("Wolf caught the rabbit at Time="+clock);
                break;
            }

            clock++;
        }
    }

    public static interlace (Location a, Location b)
    {
        // return TRUE if two locations interlace
    }
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top