lot

File*
Docs
Download
What do I make?
log in to save
Machine control
/*
@title: Sudoku Generator
@author: Ivan S.
@snapshot: 0.png
*/

const width = 120
const height = 120
const difficulty = 40

setDocDimensions(width, height)

const shapes = [];

function drawNumber(number) {
const t = new bt.Turtle();

if (number == 1) {
t.right(90);
t.forward(10);
} else if (number == 2) {
t.forward(5);
t.left(90);
t.forward(5);
t.left(90);
t.forward(5);
t.right(90);
t.forward(5);
t.right(90);
t.forward(5);
} else if (number == 3) {
t.forward(5);
t.left(90);
t.forward(5);
t.left(90);
t.forward(5);
t.left(180);
t.forward(5);
t.left(90);
t.forward(5);
t.left(90);
t.forward(5);
} else if (number == 4) {
t.left(90)
t.forward(5)
t.right(90)
t.forward(5)
t.right(90)
t.forward(5)
t.right(180)
t.forward(10)
} else if (number == 5) {
t.forward(5)
t.right(90)
t.forward(5)
t.right(90)
t.forward(5)
t.left(90)
t.forward(5)
t.left(90)
t.forward(5)
} else if (number == 6) {
t.forward(5)
t.right(180)
t.forward(5)
t.right(90)
t.forward(10)
t.right(90)
t.forward(5)
t.right(90)
t.forward(5)
t.right(90)
t.forward(5)
} else if (number == 7) {
t.forward(5)
t.left(90)
t.forward(10)
} else if (number == 8) {
t.forward(5)
t.left(90)
t.forward(10)
t.left(90)
t.forward(5)
t.left(90)
t.forward(10)
t.right(180)
t.forward(5)
t.right(90)
t.forward(5)
} else if (number == 9) {
t.left(90)
t.forward(5)
t.right(90)
t.forward(5)
t.left(90)
t.forward(5)
t.left(90)
t.forward(5)
t.left(90)
t.up()
t.forward(10)
t.down()
t.left(90)
t.forward(5)
t.left(90)
t.forward(5)
}

return t
}

function createSquare() {
const t = new bt.Turtle()

for (let i = 0; i < 2; i++) {
t.forward(width / 9)
t.right(90)
t.forward(height / 9)
t.right(90)
}

return t
}

function createBigSquare() {
const t = new bt.Turtle()

for (let i = 0; i < 2; i++) {
t.forward(width / 3)
t.right(90)
t.forward(height / 3)
t.right(90)
}

return t
}

for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
const t = createSquare()
bt.translate(t.path, [0, 0], bt.bounds(t.path).lb)
bt.translate(t.path, [width / 9 * i, height / 9 * j])
bt.join(shapes, t.lines());
}
}
for (let i = 0; i < 3; i++) {
for (let j = 0; j < 3; j++) {
const t = createBigSquare()
bt.translate(t.path, [0.3, 0.3], bt.bounds(t.path).lb)
bt.translate(t.path, [width / 3 * i, height / 3 * j])
bt.join(shapes, t.lines());
}
}

class SudokuGenerator {
constructor() {
this.rows = [];
this.cols = [];
this.nums = [];
this.board = [];

for (let i = 0; i < 9; i++) {
this.rows.push([]);
this.cols.push([]);
this.nums.push(i + 1);
this.board.push([]);
}

this.shuffle(this.nums);

for (let g = 0; g < 3; g++) {
const rowShuffle = this.shuffle([0, 1, 2]);
rowShuffle.forEach((r) => {
for (let c = 0; c < 3; c++) {
this.rows.push(g * 3 + r);
this.cols[g * 3 + c].push(g * 3 + r);
}
});
}

for (let r = 0; r < 9; r++) {
for (let c = 0; c < 9; c++) {
const num = this.nums[(3 * r + Math.floor(r / 3) + c) % 9];
this.board[r].push(num);
}
}
}

shuffle(arr) {
for (let i = arr.length - 1; i > 0; i--) {
const j = Math.floor(bt.rand() * (i + 1));
[arr[i], arr[j]] = [arr[j], arr[i]];
}
return arr;
}

createChallenge(d) {
while (d != 0) {
let mi = bt.randIntInRange(0, 9)
let bi = bt.randIntInRange(0, 9)

try {
if (this.board[mi][bi] != 0) {
this.board[mi][bi] = 0
d -= 1
}
} catch (e) {}
}
}
}


let sudoku = new SudokuGenerator();
sudoku.createChallenge(difficulty)

for (let rn = 0; rn < 9; rn++) {
let row = sudoku.board[rn]
for (let on = 0; on < 9; on++) {
if (row[on] == 0) { continue }

const obj = drawNumber(row[on])
bt.translate(obj.path, [0, 0], bt.bounds(obj.path).lb)
bt.translate(obj.path, [width / 9 * on + 2.5, height / 9 * rn + 2.5])
bt.join(shapes, obj.path)
}
}

bt.scale(shapes, [0.90, -0.90])

drawLines(shapes)

The Toolkit

This is a quick reference sheet. For full documentation refer to this.

For an introduction to Blot check out this guide.

Check out our 38 second trailer for a brief overview of the whole Blot project.

There are three names that provide functionality available in the Blot editor: setDocDimensions, drawLines, and blotToolkit (which can also be referenced as bt).

The first two affect the drawing environment itself, and the blotToolkit is used for creating line drawings.

Environment Affecting

setDocDimensions(width: number, height: number)
drawLines(polylines: [number, number][][])

Modify Polylines

Take and modify polylines in place returns first passed polylines.

These functions are available in the blotToolkit or bt object.

bt.iteratePoints(polylines, (pt, t) => { ... }) // return pt to modify, "BREAK" to split, "REMOVE" to filter out point
bt.scale(polylines, scale : scaleXY | [scaleX, scaleY], ?origin: [ x, y ]) 
bt.rotate(polylines, degrees, ?origin: [ x, y ]) 
bt.translate(polylines, [dx, dy], ?origin: [ x, y ]) 
bt.originate(polylines) // moves center to [0, 0] 
bt.resample(polylines, sampleRate) 
bt.simplify(polylines, tolerance) 
bt.trim(polylines, tStart, tEnd)
bt.merge(polylines)  
bt.join(polylines0, ...morePolylines) 
bt.copy(polylines)
bt.cut(polylines0, polylines1) 
bt.cover(polylines0, polylines1) 
bt.union(polylines0, polylines1)
bt.difference(polylines0, polylines1)
bt.intersection(polylines0, polylines1)
bt.xor(polylines0, polylines1)
bt.offset(polylines, delta, ?ops = { endType, joinType, miterLimit, arcTolerance })

Get Data From Polylines

These functions are available in the blotToolkit or bt object.

// take polylines return other
bt.getAngle(polylines, t: [0 to 1]) // returns angle in degrees
bt.getPoint(polylines, t: [0 to 1]) // returns point as [x, y]
bt.getNormal(polylines, t: [0 to 1]) // returns normal vector as [x, y]

bt.pointInside(polylines, pt)

bt.bounds(polylines) 
/*
returns { 
  xMin, xMax, 
  yMin, yMax, 
  lt, ct, rt, 
  lc, cc, rc,
  lb, cb, rb,
  width, height
}

l is left
c is center
r is right
t is top
b is bottom

they are arranged in this configuration around the bounding box of the polylines

lt--ct--rt
 |   |   |
lc--cc--rc
 |   |   | 
lb--cb--rb
*/

Generate Polylines

These functions are available in the blotToolkit or bt object.

const myTurtle = new bt.Turtle()
  .forward(distance: number)
  .arc(angle: number, radius: number)
  .goTo( [ x: number, y: number ] ) // move with up/down state
  .jump( [ x: number, y: number ] ) // move but don't draw
  .step( [ dx: number, dy: number ] ) // add delta to turtles current position
  .right(angle: number)
  .left(angle: number)
  .setAngle(angle: number)
  .up() // sets drawing to false
  .down() // sets drawing to true
  .copy()
  .applyToPath(fn) // takes (turtlePath) => { }
  .lines() // get copy of the Turtle's path

// data
const position = myTurtle.pos // [x: number, y: number]
const angle = myTurtle.angle // number
const path = myTurtle.path // is array of polylines [number, number][][]
const drawing = myTurtle.drawing // boolean
bt.catmullRom(points, ?steps = 1000) // returns polyline [number, number][]
bt.nurbs(points, ?ops = { steps: 100, degree: 2}) // returns polyline [number, number][]

Randomness

These functions are available in the blotToolkit or bt object.

bt.rand();

bt.randInRange(min: number, max: number);

bt.randIntInRange(min: number, max: number); 

bt.setRandSeed(seed: number);

bt.noise(
  number | [ x:number , ?y: number , ?z: number ], 
  { 
    octaves: number [0 to 8], 
    falloff: number [0 to 100] 
  }
);

Idioms

These are small useful code snippets.

function centerPolylines(polylines, documentWidth, documentHeight) {
  const cc = bt.bounds(polylines).cc;
  bt.translate(polylines, [documentWidth / 2, documentHeight / 2], cc);
}