Expecto Patronum 🪄

or Avada Kedavra or Wingardium Leviosa. Actually the chances of getting one of those is pretty slim. You'll probably get a light trail of a random spell...

Log in to post a comment.

// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(-.15);

const population = 0; //--min=0 max=2 step=1 (None, Square, Circle)
const turtles = 130; //min=50 max=300 step=10
const steps = 150; //min=50 max=500 step=10
const initLocation = 100; //min=40 max=150 step=10
const initDirection = 2500; //min=0 max=5000 step=5
const directionClamp = 2; //min=0.01 max=5 step=.01
const directionShare = 2; //min=.1 max=5 step=.1

const maxLocation = initLocation;
const maxDirection = 10/(initDirection === 0? 0.001: initDirection);

// 
// 2D Vector math
//

function normalize2(a) { const length = len2(a); return scale(a,length<0.0001?1:1/length); }
function len2(a) { return Math.sqrt(lensq2(a)); }
function lensq2(a) { return dot2(a,a); }
function rot2(a) { return [Math.cos(a), -Math.sin(a), Math.sin(a), Math.cos(a)]; }
function trans2(m, a) { return [m[0]*a[0]+m[2]*a[1], m[1]*a[0]+m[3]*a[1]]; }
function scale2(a,b) { return [a[0]*b,a[1]*b]; }
function add2(a,b) { return [a[0]+b[0],a[1]+b[1]]; }
function sub2(a,b) { return [a[0]-b[0],a[1]-b[1]]; }
function dist2(a,b) { return Math.hypot(...sub2(a,b)); }
function lerp2(a,b,t) { return [a[0]*(1-t)+b[0]*t,a[1]*(1-t)+b[1]*t]; }
function dot2(a,b) { return a[0]*b[0]+a[1]*b[1] }
function mulf2(v, f) { return scale2(v,f); }
function multiply2(a2x2, a) { return [(a[0]*a2x2[0])+(a[1]*a2x2[1]),(a[0]*a2x2[2])+(a[1]*a2x2[3])]; }

function clamp(i, min, max) {
    return Math.min(Math.max(i, min), max);
}

let fireflies = [];

class Firefly {
    turtle = null;
    position = [0, 0];
    direction = [0, 0];
    constructor(position, direction) {
        this.turtle = new Turtle();
        
        this.position = position;
        this.direction = direction;

        this.turtle.jump(this.position);
    }
    calibrate(fireflies) {
        let closestFly = null;
        let closestDistanceSquared = 90000;
        
        let that = this;
        for(let firefly of fireflies.filter(function (item) { return item !== that && item !== null; })) { //for some reason nulls exist sometimes in the collection
            let d = dot2(that.position, firefly.position);
            if(d < closestDistanceSquared) {
                closestDistanceSquared = d;
                closestFly = firefly;
            }
        }
        
        let distanceVector = sub2(closestFly.position, this.position);
        
        this.direction[0] += clamp(distanceVector[0] / directionShare, -directionClamp, directionClamp);
        this.direction[1] += clamp(distanceVector[1] / directionShare, -directionClamp, directionClamp);
    }
    go() {
        this.position[0] += this.direction[0];
        this.position[1] += this.direction[1];
        
        this.turtle.goto(this.position);
    }
    distanceSquared(toFirefly) {
        return Math.pow(this.position[0] - toFirefly.position[0], 2) + Math.pow(this.position[1] - toFirefly.position[1], 2);
    }
}

(function populate() {
    for(let i = 0; i < turtles; i++) {
        let x = 0;
        let y = 0;
        
        switch(population) {
            case 0:
                break;
            case 1:
                x = (Math.random() - .5) * maxLocation;
                y = (Math.random() - .5) * maxLocation;
                break;
            case 2:
                let r = this.R * Math.sqrt(Math.random()) * Math.PI / 2;
                let theta = Math.random() * 2 * Math.PI;
                
                x = Math.cos(theta) * (maxLocation / 2);
                y = Math.sin(theta) * (maxLocation / 2);
                break;
        }

        fireflies.push(new Firefly(
            [x, y],
            [(Math.random() - .5) * maxDirection, (Math.random() - .5) * maxDirection]
        ));
    }
})();

// The walk function will be called until it returns false.
function walk(i) {
    for(let firefly of fireflies) {
        firefly.calibrate(fireflies);
        firefly.go();
    }
    return i < steps;
}