Grid 011

Grid011
With Console Logging of the arrays
Which can be manually added to a Fork of Architecture 004
Architecture 004

Log in to post a comment.

// Architecture 002 — Nested Rectangles + connecting lines
// 10 November 2025
// Code from ChatGPT with 2 hours of frustrating prompting
// it's both amazing and also infuriating to work with.
// Because it's not intelegent in any sense of the word 
// Large Language Models have ZERO intelegence they are just
// statistical models.  It's like calling Excel intelegent.
//  Hope you enjoy it :-)  

const opacity = -1; // min=-1, max=1, step=0.1
Canvas.setpenopacity(opacity);

const turtle = new Turtle();

// ===== PARAMETERS =====
const parentMinX = -90;
const parentMaxX = 90;
const parentMinY = -90;
const parentMaxY = 90;

const canvasW = parentMaxX - parentMinX;
const canvasH = parentMaxY - parentMinY;

const baseCols = 7; // min=1 max=7 step=1
const baseRows = 7; // min=1 max=7 step=1
const mergeChance = 0.45; // min=0.1 max= 1 step=0.1

const parentCellMinWidth = 20;
const parentCellMaxWidth = 80;
const parentCellMinHeight = 15;
const parentCellMaxHeight = 60;

const minInset = 0.1;
const maxInset = 0.3;

const innerMinWidth = 5;
const innerMaxWidth = 60;
const innerMinHeight = 5;
const innerMaxHeight = 60;

const innerPaddingX = 10;
const innerPaddingY = 10;

const connectorLines = 15; // Number of connecting lines along each edge

// ===== DRAW MODE =====
const drawmode = 2; // 0 = Black only, 1 = White only, 2 = Both

// ===== STORAGE ARRAY =====
const corners = []; // combined array for parent + child

// ===== GRID SETUP =====
function randomProportions(n) {
    let vals = Array.from({ length: n }, () => 0.5 + Math.random());
    const sum = vals.reduce((a, b) => a + b, 0);
    return vals.map(v => v / sum);
}

const colWeights = randomProportions(baseCols);
const rowWeights = randomProportions(baseRows);
const colWidths = colWeights.map(w => w * canvasW);
const rowHeights = rowWeights.map(h => h * canvasH);

let colX = [parentMinX];
for (let i = 0; i < baseCols; i++) colX.push(colX[i] + colWidths[i]);
let rowY = [parentMinY];
for (let j = 0; j < baseRows; j++) rowY.push(rowY[j] + rowHeights[j]);

let filled = Array.from({ length: baseRows }, () => Array(baseCols).fill(false));

// ===== DRAW CELLS =====
for (let r = 0; r < baseRows; r++) {
    for (let c = 0; c < baseCols; c++) {
        if (filled[r][c]) continue;

        // Merge cells
        let mergeW = 1;
        let mergeH = 1;
        if (Math.random() < mergeChance && c < baseCols - 1 && !filled[r][c + 1]) mergeW = 2;
        if (Math.random() < mergeChance && r < baseRows - 1 && !filled[r + 1][c]) mergeH = 2;
        if (c + mergeW > baseCols) mergeW = 1;
        if (r + mergeH > baseRows) mergeH = 1;

        // Constrain size
        const tempX2 = colX[c + mergeW];
        const tempY2 = rowY[r + mergeH];
        const tempWidth = tempX2 - colX[c];
        const tempHeight = tempY2 - rowY[r];
        if (tempWidth < parentCellMinWidth || tempWidth > parentCellMaxWidth) mergeW = 1;
        if (tempHeight < parentCellMinHeight || tempHeight > parentCellMaxHeight) mergeH = 1;

        // Mark cells filled
        for (let rr = r; rr < r + mergeH; rr++) {
            for (let cc = c; cc < c + mergeW; cc++) {
                filled[rr][cc] = true;
            }
        }

        // Parent rectangle
        const px1 = colX[c];
        const px2 = colX[c + mergeW];
        const py1 = rowY[r];
        const py2 = rowY[r + mergeH];

        rectangle(px1, py1, px2, py2);

        // ===== CHILD RECTANGLE =====
        const w = px2 - px1;
        const h = py2 - py1;

        const insetFrac = minInset + Math.random() * (maxInset - minInset);
        const maxInnerWByInset = w * (1 - insetFrac);
        const maxInnerHByInset = h * (1 - insetFrac);

        const maxInnerW = Math.min(innerMaxWidth, maxInnerWByInset, w - 2 * innerPaddingX);
        const maxInnerH = Math.min(innerMaxHeight, maxInnerHByInset, h - 2 * innerPaddingY);

        const randInnerW = innerMinWidth + Math.random() * Math.max(0, maxInnerW - innerMinWidth);
        const randInnerH = innerMinHeight + Math.random() * Math.max(0, maxInnerH - innerMinHeight);

        const cx1 = px1 + innerPaddingX + Math.random() * (w - randInnerW - 2 * innerPaddingX);
        const cy1 = py1 + innerPaddingY + Math.random() * (h - randInnerH - 2 * innerPaddingY);
        const cx2 = cx1 + randInnerW;
        const cy2 = cy1 + randInnerH;

        rectangle(cx1, cy1, cx2, cy2);

// Save combined parent+child corners, rounded to 2 decimals
// Open the Console and copy the array.
// You will have to edit this to match the format used in Architecture 004
// https://turtletoy.net/turtle/9c1aa52ddb
// 0: {1: -90, 2: -90, 3: -31, 4: -41, 5: -56, 6: -72, 7: -46, 8: -64}
// 1: {1: -31, 2: -90, 3: -5, 4: -75, 5: -21, 6: -89, 7: -16, 8: -84}
// The Log from the consode needs to be manually edited to match the following format:
// {x1: -90, y1: -90, x2: -31, y2: -41, x3: -56, y3: -72, x4: -46, y4: -64, hNum: 1, vNum: 1},
// {x1: -31, y1: -90, x2: -5, y2: -75, x3: -21, y3: -89, x4: -16, y4: -84, hNum: 1, vNum: 1},
// hNum and vNum let you multiply the default number of horozontal and vertical black and whitle lines
// for any specific cells.  

corners.push({
    1: parseFloat(px1.toFixed(0)),
    2: parseFloat(py1.toFixed(0)),
    3: parseFloat(px2.toFixed(0)),
    4: parseFloat(py2.toFixed(0)),
    5: parseFloat(cx1.toFixed(0)),
    6: parseFloat(cy1.toFixed(0)),
    7: parseFloat(cx2.toFixed(0)),
    8: parseFloat(cy2.toFixed(0))
});
        // ===== CONNECT CHILD TO PARENT =====
        connectChildToParent(px1, py1, px2, py2, cx1, cy1, cx2, cy2, connectorLines, drawmode);
    }
}

// ===== FUNCTIONS =====
function rectangle(xA, yA, xB, yB) {
    turtle.penup();
    turtle.goto(xA, yA);
    turtle.pendown();
    turtle.goto(xB, yA);
    turtle.goto(xB, yB);
    turtle.goto(xA, yB);
    turtle.goto(xA, yA);
}

function connectChildToParent(px1, py1, px2, py2, cx1, cy1, cx2, cy2, lines, drawmode) {
    // TOP EDGE → White
    if (drawmode === 1 || drawmode === 2) {
        for (let i = 0; i <= lines; i++) {
            const t = i / lines;
            const childX = cx1 + t * (cx2 - cx1);
            turtle.penup();
            turtle.goto(childX, cy1);
            turtle.pendown();
            const parentX = px1 + t * (px2 - px1);
            turtle.goto(parentX, py1);
        }
    }

    // RIGHT EDGE → White
    if (drawmode === 1 || drawmode === 2) {
        for (let i = 0; i <= lines; i++) {
            const t = i / lines;
            const childY = cy1 + t * (cy2 - cy1);
            turtle.penup();
            turtle.goto(cx2, childY);
            turtle.pendown();
            const parentY = py1 + t * (py2 - py1);
            turtle.goto(px2, parentY);
        }
    }

    // BOTTOM EDGE → Black
    if (drawmode === 0 || drawmode === 2) {
        for (let i = 0; i <= lines; i++) {
            const t = i / lines;
            const childX = cx1 + t * (cx2 - cx1);
            turtle.penup();
            turtle.goto(childX, cy2);
            turtle.pendown();
            const parentX = px1 + t * (px2 - px1);
            turtle.goto(parentX, py2);
        }
    }

    // LEFT EDGE → Black
    if (drawmode === 0 || drawmode === 2) {
        for (let i = 0; i <= lines; i++) {
            const t = i / lines;
            const childY = cy1 + t * (cy2 - cy1);
            turtle.penup();
            turtle.goto(cx1, childY);
            turtle.pendown();
            const parentY = py1 + t * (py2 - py1);
            turtle.goto(px1, parentY);
        }
    }
}

// ===== OUTPUT =====
console.log("Combined parent+child corners:", corners);