Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

Top Posters

Who's Online (1)

Powered by Vanilla. Made with Bootstrap.
[Java] Boids - swarm intelligence
  • Deque
    Posts: 78
    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:
    [list=1]
    [*]separation: steer to avoid crowding local flockmates[/*:m]
    [*]alignment: steer towards the average heading of local flockmates[/*:m]
    [*]cohesion: steer to move toward the average position (center of mass) of local flockmates[/*:m][/list:o]
    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 video preview: http://tinypic.com/r/246kwwl/7
    This sample is with a low flock radius.

    Download: http://www.mediafire.com/?1qx9kafo59nd14c

    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:
    [spoiler]
    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;
    }

    }
    [/spoiler]

    Deque