diff --git a/src/array.js b/src/array.js index df69e807..d83970a0 100644 --- a/src/array.js +++ b/src/array.js @@ -1,3 +1,5 @@ +import lcg from "./lcg.js"; + export default function(x) { return typeof x === "object" && "length" in x ? x // Array, TypedArray, NodeList, array-like @@ -5,12 +7,13 @@ export default function(x) { } export function shuffle(array) { - var m = array.length, + const random = lcg(); + let m = array.length, t, i; while (m) { - i = Math.random() * m-- | 0; + i = random() * m-- | 0; t = array[m]; array[m] = array[i]; array[i] = t; diff --git a/src/lcg.js b/src/lcg.js new file mode 100644 index 00000000..a13cf79e --- /dev/null +++ b/src/lcg.js @@ -0,0 +1,9 @@ +// https://en.wikipedia.org/wiki/Linear_congruential_generator#Parameters_in_common_use +const a = 1664525; +const c = 1013904223; +const m = 4294967296; // 2^32 + +export default function() { + let s = 1; + return () => (s = (a * s + c) % m) / m; +} diff --git a/test/pack/deterministic-test.js b/test/pack/deterministic-test.js new file mode 100644 index 00000000..dc97985b --- /dev/null +++ b/test/pack/deterministic-test.js @@ -0,0 +1,13 @@ +import assert from "assert"; +import {hierarchy, stratify, pack} from "../../src/index.js"; + +it("pack is deterministic", () => { + const data = stratify().path((d) => d)([41, 41, 11, 11, 4, 4] + .flatMap((n, i) => Array.from({ length: n }, (_, j) => ({ i, j }))) + .map(({ i, j }) => `/${i}/${i}-${j}`)); + const root = hierarchy(data); + root.sum(() => 1); + const packed = Array.from(pack().size([100, 100]).padding(0)(root), + ({ x, y }) => [+x.toPrecision(5), +y.toPrecision(5)]); + assert.deepStrictEqual(packed, [[50,50],[25,50],[75,50],[50,80.443],[50,19.557],[27.269,16.539],[72.731,83.461],[21.875,50],[28.125,50],[25,55.413],[25,44.587],[18.75,44.587],[31.25,44.587],[31.25,55.413],[18.75,55.413],[15.625,50],[34.375,50],[12.5,55.413],[37.5,44.587],[28.125,60.825],[21.875,39.175],[28.125,39.175],[21.875,60.825],[25,66.238],[12.5,44.587],[25,33.762],[37.5,55.413],[34.375,60.825],[15.625,60.825],[15.625,39.175],[34.375,39.175],[40.625,60.825],[9.375,39.175],[40.625,39.175],[9.375,60.825],[9.375,50],[6.25,44.587],[40.625,50],[43.75,55.413],[31.25,66.238],[18.75,33.762],[31.25,33.762],[18.75,66.238],[21.875,28.349],[28.125,28.349],[28.125,71.651],[21.875,71.651],[6.25,55.413],[71.875,50],[78.125,50],[75,55.413],[75,44.587],[68.75,44.587],[81.25,44.587],[81.25,55.413],[68.75,55.413],[65.625,50],[84.375,50],[62.5,55.413],[87.5,44.587],[78.125,60.825],[71.875,39.175],[78.125,39.175],[71.875,60.825],[75,66.238],[62.5,44.587],[75,33.762],[87.5,55.413],[84.375,60.825],[65.625,60.825],[65.625,39.175],[84.375,39.175],[90.625,60.825],[59.375,39.175],[90.625,39.175],[59.375,60.825],[59.375,50],[56.25,44.587],[90.625,50],[93.75,55.413],[81.25,66.238],[68.75,33.762],[81.25,33.762],[68.75,66.238],[71.875,28.349],[78.125,28.349],[78.125,71.651],[71.875,71.651],[56.25,55.413],[48.438,77.736],[54.688,77.736],[51.563,83.149],[51.563,72.324],[45.313,72.324],[57.813,72.324],[57.813,83.149],[45.313,83.149],[42.188,77.736],[60.938,77.736],[39.063,83.149],[48.438,16.851],[54.688,16.851],[51.563,22.264],[51.563,11.438],[45.313,11.438],[57.813,11.438],[57.813,22.264],[45.313,22.264],[42.188,16.851],[60.938,16.851],[39.063,22.264],[24.144,16.539],[30.394,16.539],[27.269,21.952],[27.269,11.127],[69.606,83.461],[75.856,83.461],[72.731,88.873],[72.731,78.048]]); +});