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

const grid = 65; //min=1 max=200 step=1
const maxWanderLength = 40; //min=2 max=100 step=1
const wander = 0; //min=0 max=2 step=1 (Orthogonal, Diagonal, Both)
const border = 15; //min=0 max=90 step=1
const drawBorder = 1; //min=0 max=1 step=1 (No, Yes)
const barrelEffect = -.28; //min=-1 max=10 step=.01
const scaleToFitEffect = 0 //min=0 max=1 step=1 (No, Yes)

// Global code will be evaluated once.
const turtle = new Turtle();//Tortoise().addTransform();
const cellSize = (200 - border - border) / grid;
let tiles = Array.from({length: grid**2}, (v,k) => k);
const effect = Barrel(barrelEffect);

let effectScalar = 1;
if(scaleToFitEffect == 1) {
    let max = [0, 0];
    const halfPixels = cellSize * grid/2;
    for(let x = -halfPixels; x <= halfPixels; x++) {
        for(let y = -halfPixels; y <= halfPixels; y++) {
            let pt = effect([x, y]);
            max = [Math.max(max[0], pt[0]), Math.max(max[1], pt[1])];
        }
    }
    effectScalar = Math.max(halfPixels / max[0], halfPixels / max[1]);
}

const scale2 = (a, s) => [a[0]*s,a[1]*s];
const t = (c, r) => scale2(effect([(c + .5) * cellSize - 100 + border, (r + .5) * cellSize - 100 + border]), effectScalar);
function segment_intersect2(a,b,d,c) {
    const e=(c[1]-d[1])*(b[0]-a[0])-(c[0]-d[0])*(b[1]-a[1]);
    if(0==e)return false;
    c=((c[0]-d[0])*(a[1]-d[1])-(c[1]-d[1])*(a[0]-d[0]))/e;
    d=((b[0]-a[0])*(a[1]-d[1])-(b[1]-a[1])*(a[0]-d[0]))/e;
    return 0<=c&&1>=c&&0<=d&&1>=d?[a[0]+c*(b[0]-a[0]),a[1]+c*(b[1]-a[1])]:false;
}
const border_intersect2 = ((border) => {
    const borders = [[border - 100, border - 100], [100 - border, border - 100], [100 - border, 100 - border], [border - 100, 100 - border]];
    return (a, b) => {
        let pt = false;
        for(let i = 0; pt === false && i < borders.length; i++) {
            pt = segment_intersect2(borders[i], borders[(i+1) % borders.length], a, b);
        }
        return pt;
    }
})(border)
const isOutOfBounds = ((border) => {
    return (pt) => pt[0] < (border - 100) || (100 - border) < pt[0] || pt[1] < (border - 100) || (100 - border) < pt[1]
})(border)

if(drawBorder == 1) { 
    const borderTurtle = new Turtle();
    borderTurtle.jump(border / 2 - 100, border / 2 - 100);
    borderTurtle.goto(100 - border / 2, border / 2 - 100);
    borderTurtle.goto(100 - border / 2, 100 - border / 2);
    borderTurtle.goto(border / 2 - 100, 100 - border / 2);
    borderTurtle.goto(border / 2 - 100, border / 2 - 100);
}

// The walk function will be called until it returns false.
function walk(i) {
//    console.log('d', border_intersect2([0, -100], [100, 100]));

    let chosen = tiles.sort((a,b) => Math.random() < .5? -1: 1).pop();
    
    for(let i = 0; i < maxWanderLength; i++) {
        let column = chosen % grid;
        let row = chosen / grid | 0;
        
        let cp = turtle.pos();
        let pt = t(column, row);
        let cpOoB = isOutOfBounds(cp);
        let ptOoB = isOutOfBounds(pt);
        if(i == 0) {
            turtle.jump(pt);
        } else if(ptOoB) {
            if(!cpOoB) turtle.goto(border_intersect2(pt, cp));
            turtle.jump(pt);
        } else if(cpOoB) {
            turtle.jump(ptOoB? pt: border_intersect2(pt, cp));
        }
        
        turtle.goto(pt);

        tiles = tiles.filter((i) => i != chosen);

        const orthogonalCandidates = [[column, row + 1], [column + 1, row], [column, row - 1],[column - 1, row]];
        const diagonalCandidates = [[column - 1, row - 1],  [column + 1, row - 1], [column - 1, row + 1],  [column + 1, row + 1]];

        const candidates = (wander == 0? orthogonalCandidates: wander == 1? diagonalCandidates: [...orthogonalCandidates, ...diagonalCandidates])
            .filter((i) => i[0] >= 0 && i[0] < grid && i[1] >= 0 && i[1] < grid)
            .map((i) => i[1] * grid + i[0])
            .filter((i) => tiles.includes(i));
        if(candidates.length == 0) break;
        chosen = candidates.sort((a,b) => Math.random() < .5? -1: 1).pop()
    }
    return tiles.length > 0;
}

//Barrel effect shamelessly copied from Reinder's https://turtletoy.net/turtle/102cbd7c4d
function Barrel(b) { return p => { let s = (1+(p[0]**2 + p[1]**2)*b/1e4); return [p[0]*s, p[1]*s]; } }