Seedable Bubbles

Forked from Bubbles but with a seed and a minimum separation distance.

Log in to post a comment.

// Forked from "Bubbles" by troisiemetype
// https://turtletoy.net/turtle/8c5bc4d2b9

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

const seed = 0;                     //min = 0, max = 512, step = 1
const maxCircleSize = 20;           //min = 5, max = 80, step = 1
const height = 90;                  //min = 10, max = 100, step = 1
const width = 45;                   //min = 10, max = 100, step = 1
let depth = 10;                     //min = 1, max = 10, step = 0.5
const minSeparation = 1.0;          //min = 0.0, max = 20.0, step = 0.1
depth = 2**(depth * 1.5);

const traceAll = 1;                 ////min = 0, max = 1, step = 1, (no, yes)

// Seedable random number generator by David Bau: http://davidbau.com/archives/2010/01/30/random_seeds_coded_hints_and_quintillions.html
!function(a,b,c,d,e,f,g,h,i){function j(a){var b,c=a.length,e=this,f=0,g=e.i=e.j=0,h=e.S=[];for(c||(a=[c++]);d>f;)h[f]=f++;for(f=0;d>f;f++)h[f]=h[g=s&g+a[f%c]+(b=h[f])],h[g]=b;(e.g=function(a){for(var b,c=0,f=e.i,g=e.j,h=e.S;a--;)b=h[f=s&f+1],c=c*d+h[s&(h[f]=h[g=s&g+b])+(h[g]=b)];return e.i=f,e.j=g,c})(d)}function k(a,b){var c,d=[],e=typeof a;if(b&&"object"==e)for(c in a)try{d.push(k(a[c],b-1))}catch(f){}return d.length?d:"string"==e?a:a+"\0"}function l(a,b){for(var c,d=a+"",e=0;e<d.length;)b[s&e]=s&(c^=19*b[s&e])+d.charCodeAt(e++);return n(b)}function m(c){try{return o?n(o.randomBytes(d)):(a.crypto.getRandomValues(c=new Uint8Array(d)),n(c))}catch(e){return[+new Date,a,(c=a.navigator)&&c.plugins,a.screen,n(b)]}}function n(a){return String.fromCharCode.apply(0,a)}var o,p=c.pow(d,e),q=c.pow(2,f),r=2*q,s=d-1,t=c["seed"+i]=function(a,f,g){var h=[];f=1==f?{entropy:!0}:f||{};var o=l(k(f.entropy?[a,n(b)]:null==a?m():a,3),h),s=new j(h);return l(n(s.S),b),(f.pass||g||function(a,b,d){return d?(c[i]=a,b):a})(function(){for(var a=s.g(e),b=p,c=0;q>a;)a=(a+c)*d,b*=d,c=s.g(1);for(;a>=r;)a/=2,b/=2,c>>>=1;return(a+c)/b},o,"global"in f?f.global:this==c)};if(l(c[i](),b),g&&g.exports){g.exports=t;try{o=require("crypto")}catch(u){}}else h&&h.amd&&h(function(){return t})}(this,[],Math,256,6,52,"object"==typeof module&&module,"function"==typeof define&&define,"random");
Math.seedrandom('testerdetest'+(seed==1000?'':seed));
// Add a seed in seedrandom, then Math.random will use this seed

// Global code will be evaluated once.
const turtle = new Turtle();

let circles = [];

let cancelled = 0;

class Circle{
    constructor(x, y, r, trace = 1){
        // new circle candidate
        this.x = x;
        this.y = y;
        this.r = r;
        
        for(let circle of circles){
            let distX = x - circle.x;
            let distY = y - circle.y;
            
            let dist = Math.sqrt(distX**2 + distY**2);
            // first test if the center of this new circle will be in an existing circle.
            if(dist < circle.r){
/*
                console.log("circle inside");
                while(this.r > 0.1){
                    turtle.jump(this.x+this.r, this.y);
                    turtle.seth(90);
                    turtle.circle(this.r);
                    this.r -= 0.1;
                }
*/              
                cancelled++;
                return;
            }
            // then test if the circles are overlaping

            if(dist < (circle.r + this.r + minSeparation)){
                this.r = dist - circle.r - minSeparation;
                if(this.r < 0.5){
                    cancelled++;
                    return;
                }
            }
        }
        
        if(trace){
            turtle.jump(this.x+this.r, this.y);
            turtle.seth(90);
            turtle.circle(this.r);
        }
        
        cancelled = 0;
        
        circles.push(this);
    }
}

// The walk function will be called until it returns false.
function walk(i) {
    // radius
    let r = Math.random() * maxCircleSize;
    if(r < 0.3) r = 0.5;
    let trace = 1;
    if(!traceAll && r > (maxCircleSize / 3)) trace = 0;

    // location
    let x = Math.random() * 2 * (width - r) - width + r;
    let y = Math.random() * 2 * (height - r) - height + r;
    
    
    new Circle(x, y, r, trace);
    
    if(cancelled > depth){
//        console.log("run ", i, circles.length, " bubbles !");
        return false;
    }
  
    
    return true;
}