This forum is in archive mode. You will not be able to post new content.

Author Topic: [Java] Boids - Swarm intelligence  (Read 4690 times)

0 Members and 1 Guest are viewing this topic.

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
[Java] Boids - Swarm intelligence
« on: October 04, 2011, 03:43:25 PM »
Hello guys,

Boids is a well known artificial life algorithm, developed by Craig Reynolds in 1986. It simulates the behaviour of swarms by three simple rules:
  • separation: steer to avoid crowding local flockmates
  • alignment: steer towards the average heading of local flockmates
  • cohesion: steer to move toward the average position (center of mass) of local flockmates
I made no pictures for the boids, just colored circles. So it looks a bit like flying confetti or bouncy balls. There are several possibilities to improve it farther and I know there are much better implementations out there, but once I got this working I have not much interest in improving it anymore. I stumbled over it reading AI Game Programming Wisdom and wanted to try it out since then. A challenge on poisonhack made me doing so.

Have a look here for a preview: http://tinypic.com/r/246kwwl/7
This sample is with a low flock radius.

The program has some settings at startup. You can experiment a bit with them.

number of boids: should be clear
velocity limit: maximum speed
radius limit: the radius in which another boid is declared as too near, so the actual boid has to move away from it.
speed reduction: boids would be too fast without it. The higher the number, the lower the speed.
flock radius: the radius in which other boids are seen as of the same flock

Not every possible setting is reasonable. Have fun and maybe make a better one.

LOC: 504 only source
640 with comments and empty lines

Main algorithm:
Code: [Select]
package model;

import java.awt.Color;
import java.awt.Graphics;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

public class Boid {

    private static int boidNr;
    private final int panelWidth;
    private final int panelHeight;
    private Vector position;
    private Vector positionToDraw;
    private Vector velocity = new Vector(0, 0);
    private Color color;
    private final static List<Boid> boids = new LinkedList<Boid>();
    private static int updateSkip;
    private static int updates = 1;
    private static int velocityLimit;
    private static int radiusLimit;
    private static int flockRadius;

    public Boid(int pwidth, int pheight) {
        this.panelWidth = pwidth;
        this.panelHeight = pheight;
        setRandomPosition();
        setRandomColor();
    }

    public Boid(Boid boid) {
        this.panelWidth = boid.panelWidth;
        this.panelHeight = boid.panelHeight;
        this.position = new Vector(boid.position);
        this.positionToDraw = new Vector(boid.positionToDraw);
        this.velocity = new Vector(boid.velocity);
        this.color = boid.color;
    }

    public static void initBoids(int pwidth, int pheight) {
        for (int i = 0; i < boidNr; i++) {
            boids.add(new Boid(pwidth, pheight));
        }
    }

    public static void drawBoids(Graphics g) {
        for (Boid boid : boids) {
            boid.draw(g);
        }
    }

    public static void updateBoids() {
        updates++;
        if (updates == updateSkip) {
            updates = 1;
            for (Boid boid : boids) {
                boid.updateWithBounds();
            }
        }
        for (Boid boid : boids) {
            // makes the boids move slowlier
            boid.positionToDraw = new Vector(boid.position);
            boid.positionToDraw.subtract(boid.velocity);
            Vector ivel = new Vector(boid.velocity);
            ivel.multiply(updates / (double) updateSkip);
            boid.positionToDraw.add(ivel);
        }
    }

    private void setRandomPosition() {
        Random rand = new Random();
        position = new Vector();
        position.x = rand.nextInt(panelWidth);
        position.y = rand.nextInt(panelHeight);
    }

    private void draw(Graphics g) {
        g.setColor(color);
        g.fillOval((int) positionToDraw.x, (int) positionToDraw.y, 10, 10);
    }

    private void setRandomColor() {
        Random rand = new Random();
        this.color = new Color(rand.nextInt(256), rand.nextInt(256),
                rand.nextInt(256));
    }

    private void updateWithoutBounds() {
        velocity.add(rule1(), rule2(), rule3());
        limitVelocity();
        position.add(velocity);

        if (position.x > panelWidth) {
            position.x = 0;
        }
        if (position.x < 0) {
            position.x = panelWidth;
        }
        if (position.y > panelHeight) {
            position.y = 0;
        }
        if (position.y < 0) {
            position.y = panelHeight;
        }
    }

    private void updateWithBounds() {
        velocity.add(rule1(), rule2(), rule3());
        limitVelocity();
        position.add(velocity);

        if (position.x > panelWidth) {
            position.x = panelWidth;
            velocity.x = -velocity.x;
        }
        if (position.x < 0) {
            position.x = 0;
            velocity.x = -velocity.x;
        }
        if (position.y > panelHeight) {
            position.y = panelHeight;
            velocity.y = -velocity.y;
        }
        if (position.y < 0) {
            position.y = 0;
            velocity.y = -velocity.y;
        }
    }

    /**
     * boids try to fly towards the centre of mass of neighbouring boids
     *
     * @return resulting vector
     */
    private Vector rule1() {
        Vector center = new Vector(0, 0);
        List<Boid> flock = flock();
        for (Boid boid : flock) {
            if (!boid.equals(this)) {
                center.add(boid.position);
            }
        }
        center.divide(flock.size() - 1);
        Vector result = new Vector(center);
        result.subtract(this.position);
        result.divide(100);
        return result;
    }

    /**
     * try to keep a small distance away from other objects
     *
     * @return
     */
    private Vector rule2() {
        Vector result = new Vector(0, 0);
        for (Boid boid : flock()) {
            if (!boid.equals(this)) {
                if (isClose(boid.position)) {
                    Vector sub = new Vector(boid.position);
                    sub.subtract(position);
                    result.subtract(sub);
                }
            }
        }
        return result;
    }

    /**
     * boids try to match velocity with near boids
     *
     * @return
     */
    private Vector rule3() {
        Vector pvj = new Vector(0, 0);
        List<Boid> flock = flock();
        for (Boid boid : flock) {
            if (!boid.equals(this)) {
                pvj.add(boid.velocity);
            }
        }
        pvj.divide(flock.size() - 1);
        pvj.subtract(velocity);
        pvj.divide(;
        return pvj;
    }

    private void limitVelocity() {
        if (velocity.length() > velocityLimit) {
            velocity.divide(velocity.length());
            velocity.multiply(velocityLimit);
        }
    }

    public List<Boid> flock() {
        List<Boid> flock = new LinkedList<Boid>();
        for (Boid boid : boids) {
            if (isInFlock(boid.position)) {
                flock.add(boid);
            }
        }
        return flock;
    }

    private boolean isInFlock(final Vector pos) {
        Vector range = new Vector(position);
        range.subtract(pos);
        return range.length() < flockRadius;
    }

    private boolean isClose(final Vector pos) {
        Vector range = new Vector(position);
        range.subtract(pos);
        return range.length() < radiusLimit;
    }

    public static void setOptions(Options options) {
        velocityLimit = options.velocityLimit;
        radiusLimit = options.radiusLimit;
        boidNr = options.boidNr;
        updateSkip = options.speedReduction;
        flockRadius = options.flockRadius;
    }

}

Deque
« Last Edit: October 04, 2011, 03:49:29 PM by Deque »

Offline xzid

  • Knight
  • **
  • Posts: 329
  • Cookies: 41
    • View Profile
Re: [Java] Boids - Swarm intelligence
« Reply #1 on: October 05, 2011, 03:18:17 AM »
Code: [Select]
O{HAI!}
O{^get the fuck away from me, you're too close}         
    O{Hey look party! <^ way}
Code: [Select]
   O{sry :(}
          O{woo! party ^_^}
     O{:cool:}
Code: [Select]
    O{hey where u guys goin'? Wait up.}

                     O{I know it's around here somewhere}
             O{FINE! screw you guys, I'm goin' home <-}
Code: [Select]
                          O{dude slow the fuck down >:(}
                                                        O{damn wrong way, I guess it's < way}
   O{I'm lonely, wait up guyz}
               
also this:



... absolutely terrifying.

- I only do systems, have no technical input on this.

-> Srsly wtf I'm supposed to be learning calculus, I keep getting distracted.

Offline gh0st

  • Sir
  • ***
  • Posts: 575
  • Cookies: 8
  • #DEDSec
    • View Profile
Re: [Java] Boids - Swarm intelligence
« Reply #2 on: October 05, 2011, 04:01:39 AM »
wow you guys are awesome +1

Offline Deque

  • P.I.N.N.
  • Global Moderator
  • Overlord
  • *
  • Posts: 1203
  • Cookies: 518
  • Programmer, Malware Analyst
    • View Profile
Re: [Java] Boids - Swarm intelligence
« Reply #3 on: October 05, 2011, 01:46:30 PM »
Code: [Select]
O{HAI!}
O{^get the fuck away from me, you're too close}         
    O{Hey look party! <^ way}
Code: [Select]
   O{sry}
          O{woo! party ^_^}
     O{:cool:}
Code: [Select]
    O{hey where u guys goin'? Wait up.}

                     O{I know it's around here somewhere}
             O{FINE! screw you guys, I'm goin' home <-}
Code: [Select]
                          O{dude slow the fuck down}
                                                        O{damn wrong way, I guess it's < way}
   O{I'm lonely, wait up guyz}
               

I laughed my ass off.

 



Want to be here? Contact Ande, Factionwars or Kulverstukas on the forum or at IRC.