From 86ae1cf8ab017792b4d921a49d29332db7672f07 Mon Sep 17 00:00:00 2001 From: Franco Bulgarelli Date: Sun, 30 Aug 2020 20:57:34 -0300 Subject: [PATCH] Add support for padding when shuffling --- docs/js/demo.js | 4 ++-- src/canvas.js | 31 +++++++++++++++++++++++++----- src/shuffler.js | 44 ++++++++++++++++++++++++++++++++++++++++++- test/shuffler-spec.js | 30 ++++++++++++++++++++++++----- 4 files changed, 96 insertions(+), 13 deletions(-) diff --git a/docs/js/demo.js b/docs/js/demo.js index d0228ba..74426fd 100644 --- a/docs/js/demo.js +++ b/docs/js/demo.js @@ -9,12 +9,12 @@ function registerButtons(id, canvas) { }); document.getElementById(`${id}-shuffle-grid`).addEventListener('click', function() { - canvas.shuffleGrid(0.8); + canvas.shuffleGrid(1.2); canvas.redraw(); }); document.getElementById(`${id}-shuffle-columns`).addEventListener('click', function() { - canvas.shuffleColumns(0.8); + canvas.shuffleColumns(1.2); canvas.redraw(); }); diff --git a/src/canvas.js b/src/canvas.js index fe21a0c..facdb9e 100644 --- a/src/canvas.js +++ b/src/canvas.js @@ -268,13 +268,34 @@ class Canvas { this.autoconnected = true; } - shuffleColumns(farness = 0) { - this.puzzle.shuffleWith(Shuffler.columns) - this.autoconnected = true; + /** + * **Warning**: this method requires {@code maxPiecesCount} to be set. + * + * @param {number} farness + */ + shuffleColumns(farness = 1) { + this._shuffleSolution(farness, Shuffler.columns); } - shuffleGrid(farness = 0) { - this.puzzle.shuffleWith(Shuffler.grid) + /** + * **Warning**: this method requires {@code maxPiecesCount} to be set. + * + * @param {number} farness + */ + shuffleGrid(farness = 1) { + this._shuffleSolution(farness, Shuffler.grid); + } + + /** + * @private + * @param {number} farness + * @param {import('./shuffler').Shuffler} shuffler + */ + _shuffleSolution(farness, shuffler) { + this.solve(); + this.puzzle.shuffleWith(Shuffler.padder(this.proximity * 3, this.maxPiecesCount.x, this.maxPiecesCount.y)); + this.puzzle.shuffleWith(shuffler) + this.puzzle.shuffleWith(Shuffler.noise(Vector.cast(this.proximity * farness / 2))) this.autoconnected = true; } diff --git a/src/shuffler.js b/src/shuffler.js index e12f8bb..228e832 100644 --- a/src/shuffler.js +++ b/src/shuffler.js @@ -57,6 +57,46 @@ const columns = (pieces) => { }; +/** + * @param {number} padding + * @param {number} width + * @param {number} height + * @returns {Shuffler} + * */ +function padder(padding, width, height) { + return (pieces) => { + const destinations = pieces.map(it => it.centralAnchor.asVector()); + let dx = 0; + let dy = 0; + for (let j = 0; j < height; j++) { + for (let i = 0; i < width; i++) { + const destination = destinations[i + width * j]; + destination.x += dx; + destination.y += dy; + + dx += padding; + } + dx = 0; + dy += padding; + } + return destinations; + } +} + +/** + * @param {import('./vector').Vector} maxDistance + * @returns {Shuffler} + */ +function noise(maxDistance) { + return (pieces) => { + return pieces.map(it => + Anchor + .atRandom(2 * maxDistance.x, 2 * maxDistance.y) + .translate(-maxDistance.x, -maxDistance.y) + .translate(it.centralAnchor.x, it.centralAnchor.y) + .asVector()); + } +} /** * @type {Shuffler} @@ -67,5 +107,7 @@ module.exports = { random, grid, columns, - noop + noop, + padder, + noise } diff --git a/test/shuffler-spec.js b/test/shuffler-spec.js index ecd10ec..f4edad9 100644 --- a/test/shuffler-spec.js +++ b/test/shuffler-spec.js @@ -17,11 +17,11 @@ describe("shuffler", () => { puzzle = new Puzzle(); pieces = [ puzzle.newPiece({}, {centralAnchor: vector(0, 0)}), - puzzle.newPiece({}, {centralAnchor: vector(0, 10)}), puzzle.newPiece({}, {centralAnchor: vector(10, 0)}), + puzzle.newPiece({}, {centralAnchor: vector(0, 10)}), puzzle.newPiece({}, {centralAnchor: vector(10, 10)}), - puzzle.newPiece({}, {centralAnchor: vector(20, 0)}), - puzzle.newPiece({}, {centralAnchor: vector(20, 10)}), + puzzle.newPiece({}, {centralAnchor: vector(0, 20)}), + puzzle.newPiece({}, {centralAnchor: vector(10, 20)}) ]; }) @@ -32,11 +32,31 @@ describe("shuffler", () => { it("columns", () => { const result = Shuffler.columns(pieces); - assert.deepEqual(result.map(it => it.x), [0, 0, 10, 10, 20, 20]) + assert.deepEqual(result.map(it => it.x), [0, 10, 0, 10, 0, 10]) assert.equal(hasDuplicates(result), false, "There must not be any duplicates"); }) it("noop", () => { - assert.deepEqual(Shuffler.noop(pieces), [anchor(0, 0), anchor(0, 10), anchor(10, 0), anchor(10, 10), anchor(20, 0), anchor(20, 10)]) + assert.deepEqual(Shuffler.noop(pieces), [ + vector(0, 0), vector(10, 0), + vector(0, 10), vector(10, 10), + vector(0, 20), vector(10, 20) + ]) + }) + + it("noisy", () => { + assert.deepEqual(Shuffler.noise(vector(0, 0))(pieces), [ + vector(0, 0), vector(10, 0), + vector(0, 10), vector(10, 10), + vector(0, 20), vector(10, 20) + ]) + }) + + it("padder", () => { + assert.deepEqual(Shuffler.padder(5, 2, 3)(pieces), [ + vector(0, 0), vector(15, 0), + vector(0, 15), vector(15, 15), + vector(0, 30), vector(15, 30) + ]) }) })