Start with an array of sorted indices.
The Durstenfeld Shuffle works by proceeding through the array, treating one part of the array as shuffled, and the rest of the array as un-shuffled. It simply swaps each of the items in the array with a random item from the un-shuffled region until the array is fully shuffled.
All permutations will be equiprobable.
A deterministic CSPRNG (seeded with your input number) is used to generate the random indices selected during the shuffle.
const csprng = new csprng(<input number seed>);
const len = 10;
const a = new Array(len);
for(let i=0; i<len; i++) a[i] = i;
for(let i=0; i<len; i++) {
let swapIndex = nextDeterministicallyRandomIntBetween(i, len, csprng);
let tmp = a[i]; a[i] = a[swapIndex]; a[swapIndex] = tmp; // swap
}
function nextDeterministicallyRandomIntBetween(lowerBoundInclusive,
upperBoundExclusive, csprng) {
return lowerBoundInclusive +
nextDeterministicallyRandomIntLowerThan(upperBoundExclusive-lowerBoundInclusive, csprng);
}
function nextDeterministicallyRandomIntLowerThan(upperBoundExclusive, csprng) {
// determine the minimum number of bits "b" required to represent
// (upperBoundExclusive-1). Then repeatedly ask the csprng for b bits
// until it returns a result that is lower than upperBoundExclusive
let b = Math.ceil(Math.log(upperBoundExclusive) / Math.log(2));
let r;
do {
r = csprng.nextBits(b);
} while (r>=upperBoundExclusive);
return r;
}