Pisano sequence 🧮

From 'A New Way to Look at Fibonacci Numbers' by Jacob Yatsko youtube.com/watch?v=o1elkodscqw

Log in to post a comment.

const startMod = 3; //min=1 max=100 step=1
const gridSize = 6; //min=1 max=20 step=1
const spacing = 5; //min=0 max=30 step=1
const sequence = 0; //min=0 max=4 step=1 (Fibonacci, Lucas, Triangular, MultiplesOfFour, Recamán terms 600-700)
// You can find the Turtle API reference here: https://turtletoy.net/syntax
Canvas.setpenopacity(1);

// Global code will be evaluated once.
const turtle = new Turtle();
const grid = (new Grid(gridSize, spacing, 200 - spacing - spacing));

const gridIterator = grid.iterator();

const series = [[fibonacci,[0n,1n]], [fibonacci,[2n,1n]], [triangular,[]], [multiples,[4]], [recaman, [600, 700]]];

// The walk function will be called until it returns false.
function walk(i) {
    const cellItem = gridIterator.next();
    if(cellItem.done) return false;
    
    const circlePt = (i, c, r, pt) => add2(scale2([Math.sin(2 * Math.PI * i / c),-Math.cos(2 * Math.PI * i / c)], r), pt);
    
    Array.from({length:(cellItem.value.size*Math.PI)|0}).map((v, i, a) => 
        circlePt(i, a.length - 1, cellItem.value.size/2, cellItem.value.center)
    ).forEach((v, a) => turtle[a == 0?'jump':'goto'](v));

    pisano(i+startMod, series[sequence][0](...series[sequence][1]))
        .filter((v, i, a) => v != a[(i+1)%a.length]) //filter out equals in sequence
        .map((v, i, a) => [v, a[(i+1)%a.length]].sort()) //map to [from, to] pairs
        .filter((v, i, a) => !a.filter((vv, ii) => ii < i).some(vv => vv[0] == v[0] && vv[1] == v[1])) //filter out equal pairs
        .forEach(v => {
            turtle.jump(circlePt(v[0], i+startMod, cellItem.value.size/2, cellItem.value.center));
            turtle.goto(circlePt(v[1], i+startMod, cellItem.value.size/2, cellItem.value.center));
        })

    return true;
}

function* recaman(skip = 0, take = 0) {
    const sequence = [0];
    for(let i = 1; take==0||i<skip+take+1; i++) {
        if(i > skip) yield BigInt(sequence[i - 1]);
        [sequence[i-1]-i].forEach(next => sequence.push(next > 0 && !sequence.includes(next)? next: sequence[i-1]+i));
    }
}
function* multiples(base) {
    for(let n = 0n, i = BigInt(base); true; n++) {
        yield n*i;
    }
}
function* triangular() {
    for(let n = 0n, i = 1n; true; i++) {
        yield n;
        n += i;
    }
}
function* fibonacci(a = 0n, b = 1n) {
    yield a;
    yield b;
    while(true) {
        const c = a + b;
        yield c;
        a = b, b = c;
    }
}

function pisano(modulo, iterator = null) {
    const sequence = [];
    const mod = BigInt(modulo);
    let start = null;
    for(let f of iterator) {
        const nxt = f % mod;
        if(nxt === start && sequence.length % 2 == 0 && sequence.length > 0) {
            const l = sequence.length / 2;
            if(sequence.every((v, i, a) => i >= l? true: v == a[i+l])) {
                return sequence.filter((v, i) => i < l);
            }
        }
        if(start == null) start = nxt;
        sequence.push(Number(nxt));
    }
    return sequence; //if finite series
}

function add2(a, b) { return [a[0]+b[0], a[1]+b[1]]; }
function scale2(a, s) { return mul2(a, [s,s]); }
function mul2(a, b) { return [a[0]*b[0], a[1]*b[1]]; }

////////////////////////////////////////////////////////////////
// Square Grid utility code - Created by Jurgen Westerhof 2023
// https://turtletoy.net/turtle/4633bef396
////////////////////////////////////////////////////////////////
function Grid(size, spacing, canvasSize = 200, location = [0, 0], cellProperties = {}) {
    function add2(a, b) { return [a[0]+b[0], a[1]+b[1]]; }
    class Grid {
        constructor(size, spacing, canvasSize, location, cellProperties) {
            this.size = size;this.spacing = spacing;this.cellProperties = cellProperties;this.iterateMax = this.size**2 - 1;
            this.canvasSize = canvasSize;this.location = location;this.cellSize = (Math.max(0.1, (canvasSize - (size-1)*spacing)) / size);
        }
        getCellByIndex(i) {const col = i % this.size;const row = i / this.size | 0;return this.getCellByCoord(col, row);}
        getCellByCoord(col, row) {const vertice = (i) => (i + .5) * this.cellSize + i * this.spacing - this.canvasSize / 2;return {center: add2(this.location, [vertice(col), vertice(row)]),column: col,row: row,index: row * this.size + col,size: this.cellSize,spacing: this.spacing,properties: this.cellProperties,};}
        *iterator() {for(let i = 0; i <= this.iterateMax; i++) {yield this.getCellByIndex(i);}}
    }
    return new Grid(size, spacing, canvasSize, location, cellProperties);
}