Skip to content

Instantly share code, notes, and snippets.

@jketcham
Last active July 10, 2019 01:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save jketcham/9d96a5762f0ed02b9789f16a2b8e7df7 to your computer and use it in GitHub Desktop.
Save jketcham/9d96a5762f0ed02b9789f16a2b8e7df7 to your computer and use it in GitHub Desktop.
A jigsaw puzzle implementation
// Node >= v2 required
const util = require('util');
const TOP = 0;
const RIGHT = 1;
const BOTTOM = 2;
const LEFT = 3;
const SIDES = [TOP, RIGHT, BOTTOM, LEFT];
const TAB = 'tab';
const HOLE = 'hole';
const FLAT = 'flat';
function randomType() {
return Math.floor(Math.random() * 2) > 0 ? TAB : HOLE;
}
class Piece {
constructor(x, y, sides) {
this.x = x;
this.y = y;
this.sides = sides;
}
getOppositeSide(side) {
const sidePair = {
[TOP]: BOTTOM,
[RIGHT]: LEFT,
[BOTTOM]: TOP,
[LEFT]: RIGHT,
};
const oppositeSide = sidePair[side];
return this.sides[oppositeSide];
}
}
class Puzzle {
constructor(width, height) {
this.width = width;
this.height = height;
this.matrix = this.createMatrix();
this.fillMatrix();
}
createMatrix() {
const matrix = [];
while (matrix.length < this.height) {
matrix.push([]);
}
return matrix;
}
getAdjacentPieces(x, y) {
const rowAbove = this.matrix[y - 1];
const rowBelow = this.matrix[y + 1];
return [
rowAbove && rowAbove[x], // top
this.matrix[y][x + 1], // right
rowBelow && rowBelow[x], // bottom
this.matrix[y][x - 1], // left
];
}
isEdge(x, y, side) {
const tests = {
[TOP]: (x, y) => y === 0,
[RIGHT]: (x, y) => x === this.width - 1,
[BOTTOM]: (x, y) => y === this.height - 1,
[LEFT]: (x, y) => x === 0,
};
return tests[side](x, y);
}
assignSide(neighbors, side, axis) {
const isEdge = this.isEdge(...axis, side);
if (isEdge) {
return FLAT;
}
const adjacentPiece = neighbors[side];
if (!adjacentPiece) {
return randomType();
}
if (adjacentPiece.getOppositeSide(side) === TAB) {
return HOLE;
}
return TAB;
}
fillMatrix() {
this.matrix.forEach((row, yIndex) => {
while (row.length < this.width) {
const xIndex = row.length;
const axis = [xIndex, yIndex];
const adjacentPieces = this.getAdjacentPieces(...axis);
const sides = SIDES.map(side => this.assignSide(adjacentPieces, side, axis));
row.push(new Piece(xIndex, yIndex, sides));
}
});
}
}
const puzzle = new Puzzle(4, 4);
console.log(util.inspect(puzzle.matrix, false, null, true));
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment