### Connections on grid ✏️

Create lines from a position to random offset, but a point may be touched only few times. Its simple and random, but since everything is drawn on grid positions, it looks like there is still order.

Update; added some fun tortoise transfoms on it

```// Forked from "Rectangles 📦" by markknol
// https://turtletoy.net/turtle/1739b05a12
const turtle = new Tortoise();
function Wave(f, a) { return p => [p[0], p[1]+Math.sin(p[0]*f)*a]; }
function Scale(s) { return p => [p[0]*s, p[1]*s]; }
function Barrel(b) { return p => { let s = (1+(p[0]**2 + p[1]**2)*b/1e4); return [p[0]*s, p[1]*s]; } }
const barrel = -0.0; // min=-2, max=1, step=0.001
const waveF = -0.0;  // min=-1, max=1, step=0.001
const waveA = 0;  // min=-3, max=13, step=0.1

const scale = 1.0;  // min=0.5, max=2, step=0.01

const width = 25; // min=5, max=50, step=1
const height = 25; // min=5, max=50, step=1

const size = 200 - 20;

let grid;

// The walk function will be called until it returns false.
function walk(i) {
if (grid == null) grid = new LazyGrid(width,height);
const x1 = (Math.random() * width) | 0;
const y1 = (Math.random() * height) | 0;

const movement = 2; // min=1, max=5, step=1
const amount1 = (1 + Math.random() * movement) | 0;
const x2 = x1 + (Math.random() > 0.5 ? -amount1 : amount1);
const amount2 = (1 + Math.random() * movement) | 0;
const y2 = y1 + (Math.random() > 0.5 ? -amount2 : amount2);

if (x2 < 0 || y2 < 0 || x2 >= width || y2 >= height) return true;

if (x2 !== x1 && y1 !== y2) {
const g1 = grid.get(x1,y1);
const g2 = grid.get(x2,y2);
const connections = 2; // min=1, max=10, step=1
if (g1 < connections && g2 < connections) {
grid.set(x1,y1, g1 + 1);
grid.set(x2,y2, g2 + 1);

turtle.jump(-size/2 + x1 * size/(width-1), -size/2 + y1 * size/(height-1));
turtle.goto(-size/2 + x2 * size/(width-1), -size/2 + y2 * size/(height-1));
}
}

return i<width*height*10;
}

class LazyGrid {
constructor(width, height) {
const data = {}
this._data = data;

for (let y=0; y<height; y++) {
for (let x=0; x<width; x++) {
if (!data[x]) data[x] = {};
if (!data[x][y]) data[x][y] = 0;
}
}
}
set(x,y, value) {
this._data[x][y] = value;
}
get(x,y) {
return this._data[x][y];
}
}

////////////////////////////////////////////////////////////////
// Tortoise utility code (Minimal Turtle and Transforms)
// https://turtletoy.net/turtle/102cbd7c4d
////////////////////////////////////////////////////////////////

function Tortoise(x, y) {
class Tortoise extends Turtle {
constructor(x, y) {
super(x, y);
this.ps = Array.isArray(x) ? [...x] : [x || 0, y || 0];
this.transforms = [];
}
this.transforms.push(t);
this.jump(this.ps);
return this;
}
applyTransforms(p) {
if (!this.transforms) return p;
let pt = [...p];
this.transforms.map(t => { pt = t(pt); });
return pt;
}
goto(x, y) {
const p = Array.isArray(x) ? [...x] : [x, y];
const pt = this.applyTransforms(p);
if (this.isdown() && (this.pt[0]-pt[0])**2 + (this.pt[1]-pt[1])**2 > 4) {
this.goto((this.ps[0]+p[0])/2, (this.ps[1]+p[1])/2);
this.goto(p);
} else {
super.goto(pt);
this.ps = p;
this.pt = pt;
}
}
position() { return this.ps; }
}
return new Tortoise(x,y);
}
```