Radio Shack

Attempting to build these circuits is highly unadvisable.

Log in to post a comment.

const branchingChance = 1.0; // min=0.01, max=1.0, step=0.01
const branchingMultiplier = 1; // min=0, max=1, step=0.01
const branchingDeathChance = 0.6; // min=0.01, max=1.0, step=0.01
const multiLeadComponentChance = 1.0; // min=0.01, max=1.0, step=0.01
const twoLeadComponentChance = 1.0; // min=0.01, max=1.0, step=0.01
const lineChance = 0.2; // min=0.01, max=1.0, step=0.01
const turnChance = 0.2; // min=0.01, max=1.0, step=0.01
const energyLossMultiplier = 0.5; // min=0.01, max=1.0, step=0.01

Turtle.prototype.drawResistor = function() {
    const angle = 60;
    const connector = 4*scale;
    this.pendown();
    this.forward(connector);
    this.left(angle);
    this.forward(1*scale);
    this.right(2*angle);
    this.forward(2*scale);
    this.left(2*angle);
    this.forward(2*scale);
    this.right(2*angle);
    this.forward(2*scale);
    this.left(2*angle);
    this.forward(2*scale);
    this.right(2*angle);
    this.forward(2*scale);
    this.left(2*angle);
    this.forward(1*scale);
    this.right(angle);
    this.forward(connector);
    this.penup();
    this.energy *= 0.95;
}

Turtle.prototype.drawInductor = function() {
    const connector = 4*scale;
    const radius = 1.5*scale;
    this.pendown();
    this.forward(connector);
    this.penup();
    for (let i = 0; i < 3; i++) {
        this.left(90);
        this.pendown();
        this.circle(radius, 180, 40);
        this.penup();
        this.left(90);
    }
    this.pendown();
    this.forward(connector);
    this.penup();
    this.energy *= 0.9;
}

Turtle.prototype.drawDiode = function() {
    const connector = 4*scale;
    const base = 1.5*scale;
    const length = 2.5*scale;
    const side = Math.sqrt(base*base+length*length);
    const a = Math.atan(length/base)*180/Math.PI;
    this.pendown();
    this.forward(connector);
    this.left(90);
    this.forward(base);
    this.right(180-a);
    this.forward(side);
    this.left(90-a);
    this.right((a-270)%360);
    this.forward(side);
    this.right(180-a);
    this.forward(base);
    this.penup();
    this.right(90);
    this.forward(length);
    this.left(90);
    this.backward(base);
    this.pendown();
    this.forward(2*base);
    this.penup();
    this.backward(base);
    this.right(90);
    this.pendown();
    this.forward(connector);
    this.energy *= 0.97;
    this.penup();
}

Turtle.prototype.drawReverseDiode = function () {
    this.penup();
    this.forward(10.5*scale);
    const helper = this.clone();
    helper.seth((this.h()-180)%360);
    helper.drawDiode();
}

Turtle.prototype.drawZenerDiode = function() {
    const connector = 4*scale;
    const base = 1.5*scale;
    const length = 2.5*scale;
    const side = Math.sqrt(base*base+length*length);
    const a = Math.atan(length/base)*180/Math.PI;
    this.pendown();
    this.forward(connector);
    this.left(90);
    this.forward(base);
    this.right(180-a);
    this.forward(side);
    this.left(90-a);
    this.right((a-270)%360);
    this.forward(side);
    this.right(180-a);
    this.forward(base);
    this.penup();
    this.right(90);
    this.forward(length);
    this.left(90);
    this.backward(base);
    this.left(60);
    this.backward(base/2);
    this.pendown();
    this.forward(base/2);
    this.right(60);
    this.forward(2*base);
    this.left(60);
    this.forward(base/2);
    this.penup();
    this.backward(base/2);
    this.right(60);
    this.backward(base);
    this.right(90);
    this.pendown();
    this.forward(connector);
    this.energy *= 0.97;
    this.penup();
}

Turtle.prototype.drawRectifier = function() {
    const connector = 4*scale;
    let newTurtles = [];
    this.pendown();
    this.forward(connector);
    const helper = this.clone();
    this.left(45);
    this.drawDiode();
    const a = this.clone();
    a.left(45);
    a.forward(connector);
    a.drawLine();
    newTurtles.push(a);
    this.right(90);
    this.drawDiode();
    this.left(45);
    this.pendown();
    this.forward(connector);
    this.penup();
    helper.right(45);
    helper.drawDiode();
    const b = helper.clone();
    b.right(45);
    b.forward(connector);
    b.drawLine();
    newTurtles.push(b);
    helper.left(90);
    helper.drawDiode();
    this.energy *= 0.1;
    newTurtles = newTurtles.map(t => {
        t.energy = this.energy / 2;
        return t;
    })
    return newTurtles;
}

Turtle.prototype.drawTransistor = function() {
    const connector = 8*scale;
    const radius = 4*scale;
    this.energy *= 0.5;
    this.pendown();
    this.forward(connector);
    this.right(75);
    this.forward(radius/1.5);
    this.left(75);
    this.penup();
    this.backward(1.5*scale);
    this.pendown();
    this.forward(1.5*scale+radius/4);
    const helper = this.clone();
    this.forward(1.5*scale+radius/4);
    this.penup();
    this.backward(1.5*scale);
    this.left(75);
    this.pendown();
    this.forward(radius/1.5);
    this.right(75);
    this.forward(connector);
    this.penup();
    helper.right(90);
    helper.forward(radius/2);
    helper.right(90);
    helper.circle(radius);
    helper.left(90);
    helper.forward(connector);
    return [helper.spawn(1)];
}

Turtle.prototype.drawOpAmp = function() {
    const connector = 6*scale;
    const base = 3*scale;
    const length = 5*scale;
    const side = Math.sqrt(base*base+length*length);
    const a = Math.atan(length/base)*180/Math.PI;
    const h = Math.round(this.h())%360;
    this.energy *= 0.8;
    this.pendown();
    if (this.h() === 180) {
        this.left(45);
        this.forward(connector);
        this.left(45);
        this.forward(connector);
        this.left(45);
    }
    this.edgeRotate(0);
    this.seth(0);
    this.forward(connector);
    this.left(90);

    this.penup();
    this.forward(base/2);
    this.right(180-a);
    this.pendown();
    this.forward(side);
    this.left(90-a);

    const newTurtle = this.clone();
    newTurtle.forward(connector);

    this.right((a-270)%360);
    this.forward(side);
    this.right(180-a);
    this.forward(2*base);
    this.penup();
    this.backward(3*base/2);
    this.pendown();
    this.left(90);
    this.forward(connector);
    this.penup();
    
    return [newTurtle];
}

Turtle.prototype.drawCapacitor = function() {
    const connector = 4*scale;
    const base = 3*scale;
    const gap = 1*scale;
    this.pendown();
    this.forward(connector);
    this.left(90);
    this.penup();
    this.backward(base/2);
    this.pendown();
    this.forward(base);
    this.penup();
    this.right(90);
    this.forward(gap);
    this.left(90);
    this.pendown();
    this.backward(base);
    this.penup();
    this.forward(base/2);
    this.right(90);
    this.pendown();
    this.forward(connector);
    this.penup();
    this.energy *= 0.9;
}

Turtle.prototype.drawGround = function() {
    const connector = 4*scale;
    const base = 3*scale;
    const gap = 1*scale;

    this.pendown();
    this.forward(connector);
    this.edgeRotate(90);
    this.seth(90);
    this.forward(base);
    this.penup();
    this.left(90);
    this.backward(base/2);
    const x = this.x();
    for (let i = 0; i < 3; i++) {
        this.forward(i*base/5);
        this.pendown();
        this.forward(base-i*2*base/5);
        this.penup();
        this.setx(x);
        this.sety(this.y()+gap);
    }
    this.energy = 0;
}

Turtle.prototype.drawSignalGround = function() {
    const connector = 4*scale;
    const base = 1.5*scale;
    const gap = 1*scale;
    const length = 2.5*scale;
    const side = Math.sqrt(base*base+length*length);
    const a = Math.atan(length/base)*180/Math.PI;
    this.pendown();
    this.forward(connector);
    this.edgeRotate(90);
    this.seth(90);
    this.forward(connector);
    this.left(90);
    this.forward(base);
    this.right(180-a);
    this.forward(side);
    this.left(90-a);
    this.right((a-270)%360);
    this.forward(side);
    this.right(180-a);
    this.forward(base);
    this.right(90);
    this.penup();
    this.forward(length);
    this.energy = 0;
}

Turtle.prototype.drawVcc = function() {
    const connector = 4*scale;
    const base = 1.5*scale;
    const gap = 1*scale;
    const length = 2.5*scale;
    const side = Math.sqrt(base*base+length*length);
    const a = Math.atan(length/base)*180/Math.PI;
    this.pendown();
    this.forward(connector);
    this.edgeRotate(270);
    this.seth(270);
    this.forward(connector);
    this.penup();
    this.left(90);
    this.forward(base);
    this.pendown();
    this.right(180-a);
    this.forward(side);
    this.left(90-a);
    this.right((a-270)%360);
    this.forward(side);
    this.right(180-a);
    this.penup();
    this.forward(base);
    this.right(90);
    this.pendown();
    this.forward(length);
    this.penup();
    this.energy = 0;
}

Turtle.prototype.drawInput = function() {
    const connector = 2*scale;
    const base = scale;
    this.pendown();
    this.forward(connector);
    this.edgeRotate(180);
    this.seth(180);
    this.forward(connector);
    this.penup();
    this.left(90);
    this.forward(base/2);
    this.right(90);
    this.pendown();
    this.forward(base);
    this.circle(base);
    this.penup();
    this.energy = 0;
}

Turtle.prototype.drawOutput = function() {
    const connector = 2*scale;
    const length = 2*scale;
    const base = scale;
    const side = Math.sqrt(base*base+length*length);
    const a = Math.atan(length/base)*180/Math.PI;
    this.pendown();
    this.forward(connector);
    this.edgeRotate(0);
    this.seth(0);
    this.forward(connector);
    this.penup();
    this.left(90);
    this.forward(base);
    this.pendown();
    this.right(180-a);
    this.forward(side);
    this.left(90-a);
    this.right((a-270)%360);
    this.forward(side);
    this.right(180-a);
    this.penup();
    this.forward(base);
    this.right(90);
    this.pendown();
    this.forward(length);
    this.penup();
    this.energy = 0;
}

Turtle.prototype.drawLine = function() {
    const lut = [4, 7, 9];
    const len = lut[Math.floor(Math.random()*lut.length)]*scale;
    this.penup();
    this.forward(len);
    if (Math.abs(this.y()) > 80 || Math.abs(this.x()) > 70) {
        this.backward(len);
        this.end();
    } else {
        this.backward(len);
        this.pendown();
        this.forward(len);
        this.penup();
        this.energy *= 0.99;
    }
    
}

Turtle.prototype.drawConnector = function() {
    const size = 6;
    const x = this.x();
    const y = this.y();
    for (let n = 1; n < size; n++) {
        this.left(90);
        this.forward(n/size);
        this.right(90);
        this.pendown();
        this.circle(n/size);
        this.penup();
        this.left(90);
        this.backward(n/size);
        this.right(90);
    }
    this.goto(x,y);
    this.penup();
}

Turtle.prototype.edgeRotate = function(dir) {
    const connector = 4*scale;
    const h = Math.round(this.h())%360;
    const left = this.x() > 0 ? this.left : this.right;
    const right = this.x() > 0 ? this.right : this.left;
    let angle = (h-(dir+360))%360;
    for (let i = 0; angle > 0; i++, angle-=45) {
        if (dir > 270 || dir < 90) {
            left.call(this, 45);
        } else {
            right.call(this, 45);
        }
        this.forward(i%2==1 ? 2*connector : connector);
    }
}

Turtle.prototype.spawn = function(n) {
    const newTurtle = this.clone();
    newTurtle.right(n%2==0 ? 90 : 270);
    newTurtle.drawLine();
    newTurtle.energy = this.energy / (1+Math.random());
    return newTurtle;
}

Turtle.prototype.end = function() {
    const h = Math.round(this.h())%360;
    if (h === 270) {
        this.topEnders[Math.floor(Math.random()*this.topEnders.length)].call(this);
    }
    else if (h === 0) {
        this.rightEnders[Math.floor(Math.random()*this.rightEnders.length)].call(this);
    }
    else if (h === 90) {
        this.bottomEnders[Math.floor(Math.random()*this.bottomEnders.length)].call(this);
    }
    else if (h === 180) {
        this.leftEnders[Math.floor(Math.random()*this.leftEnders.length)].call(this);
    }
    
    else if (this.y() > 0) {
        if (this.y() < 60 && this.x() > 60) {
            this.rightEnders[Math.floor(Math.random()*this.rightEnders.length)].call(this);
        } else {
            this.bottomEnders[Math.floor(Math.random()*this.bottomEnders.length)].call(this);
        }
    } else {
        if (this.y() > -60 && this.x() < -60) {
            this.leftEnders[Math.floor(Math.random()*this.leftEnders.length)].call(this);
        } else {
            this.topEnders[Math.floor(Math.random()*this.topEnders.length)].call(this);
        }
    }
}

Turtle.prototype.fns = [
    Turtle.prototype.drawResistor,
    Turtle.prototype.drawInductor,
    Turtle.prototype.drawDiode,
    Turtle.prototype.drawReverseDiode,
    Turtle.prototype.drawZenerDiode,
    Turtle.prototype.drawCapacitor,
];

Turtle.prototype.spawners = [
    Turtle.prototype.drawRectifier,
    Turtle.prototype.drawTransistor,
    Turtle.prototype.drawOpAmp,
];

Turtle.prototype.leftEnders = [
    Turtle.prototype.drawInput,
];

Turtle.prototype.rightEnders = [
    Turtle.prototype.drawOutput,
];

Turtle.prototype.topEnders = [
    Turtle.prototype.drawVcc,
];

Turtle.prototype.bottomEnders = [
    Turtle.prototype.drawGround,
    Turtle.prototype.drawSignalGround,
]

let scale = 1;
const initialEnergy = 1000;
const maxNodes = 1000;

Canvas.setpenopacity(1);
const topTurtle = new Turtle();
topTurtle.energy = initialEnergy;
topTurtle.penup();
topTurtle.goto(0,0);
topTurtle.seth(Math.random() > 0.5 ? 270 : 180);
const bottomTurtle = topTurtle.clone();
bottomTurtle.seth((bottomTurtle.h()+180)%360)
let turtles = [topTurtle,bottomTurtle];
let livingTurtles = [];
let newTurtles = [];
let skipped = false;
let nodes = 0;

function walk(i) {
    newTurtles = livingTurtles = [];
    turtles.map((turtle, idx) => {
        if (turtle.energy < 1 && turtle.energy > 0) {
            if (turtle.y() > 0) {
                turtle.drawGround();
            } else {
                turtle.drawVcc();
            }
        }
        if (turtle.energy < 1 || turtle.x() > 100 || turtle.y() > 100 || turtle.x() < -100 || turtle.y() < -100) {
            turtles[idx] = null;
        } else {
            skipped = false;
            // Branching
            if (Math.random()*branchingChance > 0.99525) {
                turtle.drawConnector();
                for (let h = branchingMultiplier+Math.round(Math.random()); h > 0; h--) {
                    newTurtles.push(turtle.spawn(h));
                }
                // Sometimes, kill the original turtle, so a T-connection is created.
                if (newTurtles.length === 2 && Math.random() >= branchingDeathChance) {
                    turtles[idx] = null;
                }
            }
            // Components with more than 2 leads
            else if (i > 5 && Math.random()*multiLeadComponentChance > 0.9925) {
                const possiblyTurtles = turtle.spawners[Math.floor(Math.random()*turtle.spawners.length)].call(turtle);
                if (!!possiblyTurtles && possiblyTurtles.length) {
                    newTurtles = newTurtles.concat(possiblyTurtles);
                }
                nodes++;
            }
            // Components
            else if (i > 1 && Math.random()*twoLeadComponentChance > 0.95) {
                const possiblyTurtles = turtle.fns[Math.floor(Math.random()*turtle.fns.length)].call(turtle);
                if (!!possiblyTurtles && possiblyTurtles.length) {
                    newTurtles = newTurtles.concat(possiblyTurtles);
                }
                nodes++;
            }
            // Voltages and grounds
            else if (i > 15 && (Math.abs(turtle.y()) > 70 || Math.abs(turtle.x()) > 70)) {
                turtle.end();
                nodes++;
            }
            // Lines
            else if (Math.random() <= lineChance) {
                turtle.drawLine();
            }
            else {
                skipped = true;
            }
            
            // Turning
            if (!skipped && Math.random() < turnChance) {
                Math.random() > 0.5 
                    ? turtle.left((i%5!==0 && Math.random() < 0.9) ? 45 : 90) 
                    : turtle.right((i%7!==0 && Math.random() < 0.9) ? 45 : 90);
            }
    
            turtle.energy *= energyLossMultiplier;
        }
    })
    livingTurtles = turtles.filter(t => t != null);
    turtles = livingTurtles.concat(newTurtles);
    return nodes < maxNodes && turtles.length != 0;
}