Skip to content

Instantly share code, notes, and snippets.

@JosePedroDias
Created December 2, 2023 19:08
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 JosePedroDias/30882b0988e822c389ed5b4115fc3e18 to your computer and use it in GitHub Desktop.
Save JosePedroDias/30882b0988e822c389ed5b4115fc3e18 to your computer and use it in GitHub Desktop.
returns random outcomes based on a configuration of their weights
// array of [outcome, weight]
export function weightedRandom(arr) {
const outcomeCuts = [];
let accum = 0;
for (const [out, weight] of arr) {
accum += weight;
outcomeCuts.push([out, accum]);
}
const r = accum * Math.random();
let best;
outcomeCuts.reverse();
for (const [out, cutAt] of outcomeCuts) {
if (r <= cutAt) best = out;
else break;
}
return best;
}
import test from 'node:test';
import { ok } from 'node:assert/strict';
import { weightedRandom } from './weightedRandom.mjs';
test('weightedRandom', (_t) => {
const config = [
['a', 60], // 60% or 0.6
['b', 30], // 30% or 0.3
['c', 10], // 10% or 0.1
];
const numRuns = 10000;
const histo = { a: 0, b: 0, c: 0 };
for (let i = 0; i < numRuns; ++i) {
const outcome = weightedRandom(config);
++histo[outcome];
}
for (const k of Object.keys(histo)) histo[k] /= numRuns;
const e = 0.01;
ok(histo.a > 0.6 - e && histo.a < 0.6 + e);
ok(histo.b > 0.3 - e && histo.b < 0.3 + e);
ok(histo.c > 0.1 - e && histo.c < 0.1 + e);
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment