Basic Truchet tiling

Play with x_rand and y_rand to create non-random patterns.

Log in to post a comment.

// LL 2021

Canvas.setpenopacity(1);

const grid_size = 50; // min=1 max=200 step=1
const precision = 5; // min=1 max=10 step=1
const x_rand = 0; // min=0 max=1000 step=1
const y_rand = 0; // min=0 max=1000 step=1
const rotation = 1; // min=0 max=1 step=1
const line_count = 5; // min=1 max=29 step=2
const draw_bounds = 0; // min=0 max=1 step=1 (No,Yes)
const seed = 0; // min=0 max=100 step=1

const canvas_size = 300;
const grid_step = canvas_size / grid_size;

const turtle = new Turtle();

var tiles;

function walk(i) {
    if (i==0) {
        initTiles();
    }
    
    if (tiles.length > 0) {
        const tile = tiles.shift();
        
        tile.draw();
    }
    
    return tiles.length > 0;
}

function initTiles() {
    tiles = [];
    for (var y=0; y<grid_size; y++) {
        for (var x=0; x<grid_size; x++) {
            const o = random(x, y);
            tiles.push(new Tile(x, y, o));
        }
    }
}

class Tile {
    constructor(x, y, orientation) {
        this.orientation = orientation;
        this.x = x;
        this.y = y;
    }
    
    draw() {
        const angle = Math.floor(this.orientation * 2) * Math.PI / 2 + Math.PI / 4;
        const r = rotation * Math.PI / 4;
        const cx = -canvas_size / 2 + this.x * grid_step + grid_step / 2;
        const cy = -canvas_size / 2 + this.y * grid_step + grid_step / 2;
        const dx = rotX(cx, cy, r);
        const dy = rotY(cx, cy, r);
        
        if (draw_bounds) {
            const dr = grid_step / Math.sqrt(2);
            turtle.up();
            for (var s=0.5; s<=4.5; s++) {
                turtle.goto(dx + Math.cos(r + s * Math.PI/2) * dr, dy + Math.sin(r + s * Math.PI/2) * dr);
                turtle.down();
            }
        }
        
        const count = Math.floor(line_count / 2);
        for (var o=-count; o<=count; o++) {
            const ro = grid_step / 2 * (1 + o / 10);
            
            for (var s=0; s<2; s++) {
                const ox = dx + Math.cos(angle + r + s * Math.PI) * grid_step / Math.sqrt(2);
                const oy = dy + Math.sin(angle + r + s * Math.PI) * grid_step / Math.sqrt(2);
                
                turtle.up();
                const step = Math.PI/2 / precision;
                for (var a=0; a<Math.PI/2+step/2; a+=step) {
                    const bx = ox + Math.cos(a + r + angle + s * Math.PI + 3 * Math.PI / 4) * ro;
                    const by = oy + Math.sin(a + r + angle + s * Math.PI + 3 * Math.PI / 4) * ro;
                    turtle.goto(bx, by); turtle.down();
                }
            }
        }
    }
}

function rotX(x, y, a) { return Math.cos(a) * x - Math.sin(a) * y; }
function rotY(x, y, a) { return Math.sin(a) * x + Math.cos(a) * y; }

var rng;
function random(x, y) {
    if (x_rand > 0 || y_rand > 0) {
        return ((seed+1) * (x * x_rand + y * y_rand)) / 1000;
    }
    
    if (seed == 0) return Math.random();
    rng = new RNG(seed + x + y * 1000);
    for (var skip=0; skip < 100; skip++) rng.nextFloat();
    return rng.nextFloat();
}

// Random with seed
function RNG(t){return new class{constructor(t){this.m=2147483648,this.a=1103515245,this.c=12345,this.state=t||Math.floor(Math.random()*(this.m-1))}nextFloat(){return this.state=(this.a*this.state+this.c)%this.m,this.state/(this.m-1)}}(t)}