Turtle Cloning

At each step, all turtles either step forward with pen down, step forward with pen up, or make two copies of themselves.

Log in to post a comment.

// Parameters
Canvas.setpenopacity(1);
const numSteps = 20;
const initialStepSize = 24;
const stepSizeDecay = 0.9;
const branchAngle = 120;

const numTurtles = 2;
const initialAngle = 30;

const stepWeight = 2;
const cloneWeight = 1;
const drawWeight = 2;

let actionSequence = "";


function setup() {
    let turtles = [...Array(numTurtles)].map(n => new Turtle());

    for (var i = 0; i < turtles.length; i++) {
        let turtle = turtles[i];
        turtle.penup();
        turtle.goto(0, 0);
        turtle.seth((360 * i / numTurtles) + initialAngle);
        turtle.pendown();
    }

    return turtles;
}

function weightedRandomSelection(choices, weights) {
    let weightSum = 0.0;
    for (var i = 0; i < weights.length; i++) { weightSum += weights[i]; }

    let rand = Math.random() * weightSum;
    let cumulativeSum = 0.0;
    let idx = 0;
    while (cumulativeSum < rand) {
        idx++;
        cumulativeSum += weights[idx];
    }
    return choices[idx - 1];

}

function generateActionSequence() {
    let sequence = "";

    for (var i = 0; i < numSteps; i++) {
        let choices;
        let weights;

        if (sequence.length == 0 || sequence[sequence.length - 1] == "0") {
            choices = [1, 2];
            weights = [drawWeight, stepWeight];
        } else {
            choices = [0, 1, 2];
            weights = [cloneWeight, drawWeight, stepWeight];
        }

        sequence += weightedRandomSelection(choices, weights);
    }

    return sequence;
}

let stepSize = initialStepSize;
let turtles = setup();
actionSequence = actionSequence || generateActionSequence();
console.log(actionSequence);

function step(n) {
    let newTurtles = []; 

    for (var i = 0; i < turtles.length; i++) {
        let turtle = turtles[i];
        let currentAction = actionSequence[n % actionSequence.length];

        if (currentAction == 0) {
            let newTurtle1 = turtle.clone();
            newTurtle1.right(branchAngle);
            newTurtles.push(newTurtle1);

            let newTurtle2 = turtle.clone();
            newTurtle2.left(branchAngle);
            newTurtles.push(newTurtle2);
        } else if (currentAction == 1) {
            turtle.forward(stepSize);
        } else if (currentAction == 2) {
            turtle.penup();
            turtle.forward(stepSize);
            turtle.pendown();
        }
    }

    turtles = turtles.concat(newTurtles);
    stepSize *= stepSizeDecay;
}

function walk(i) {
    step(i);
    return i < numSteps;
}