@simcups/chance-utils 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chance.d.ts +6 -0
- package/dist/chance.d.ts.map +1 -0
- package/dist/chance.js +19 -0
- package/dist/chance.js.map +1 -0
- package/dist/clamp.d.ts +4 -0
- package/dist/clamp.d.ts.map +1 -0
- package/dist/clamp.js +11 -0
- package/dist/clamp.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/weighted-sample.d.ts +15 -0
- package/dist/weighted-sample.d.ts.map +1 -0
- package/dist/weighted-sample.js +66 -0
- package/dist/weighted-sample.js.map +1 -0
- package/package.json +25 -0
package/dist/chance.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare function randomInteger(min: number, max: number): number;
|
|
2
|
+
export declare function randomFloat(min: number, max: number): number;
|
|
3
|
+
export declare function chance(likelihood?: number, max?: number): boolean;
|
|
4
|
+
export declare function weightedBool(trueLikelihood: number, falseLikelihood: number): boolean;
|
|
5
|
+
export declare function sample<T>(array: T[]): T | undefined;
|
|
6
|
+
//# sourceMappingURL=chance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chance.d.ts","sourceRoot":"","sources":["../src/chance.ts"],"names":[],"mappings":"AAGA,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,UAErD;AAED,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAG5D;AAED,wBAAgB,MAAM,CAAC,UAAU,GAAE,MAAW,EAAE,GAAG,GAAE,MAAU,GAAG,OAAO,CAExE;AAED,wBAAgB,YAAY,CAC1B,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,GACtB,OAAO,CAET;AAED,wBAAgB,MAAM,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,iBAEnC"}
|
package/dist/chance.js
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { clampLikelihood } from "./clamp.js";
|
|
2
|
+
import { weightedSample } from "./weighted-sample.js";
|
|
3
|
+
export function randomInteger(min, max) {
|
|
4
|
+
return Math.floor(Math.random() * (max - min + 1)) + min;
|
|
5
|
+
}
|
|
6
|
+
export function randomFloat(min, max) {
|
|
7
|
+
const randomNum = Math.random() * (max - min) + min;
|
|
8
|
+
return Math.round(randomNum * 100) / 100; // Round to two decimal places
|
|
9
|
+
}
|
|
10
|
+
export function chance(likelihood = 50, max = 0) {
|
|
11
|
+
return randomInteger(1, 100) <= clampLikelihood(Math.max(likelihood, max));
|
|
12
|
+
}
|
|
13
|
+
export function weightedBool(trueLikelihood, falseLikelihood) {
|
|
14
|
+
return weightedSample([true, false], [trueLikelihood, falseLikelihood]);
|
|
15
|
+
}
|
|
16
|
+
export function sample(array) {
|
|
17
|
+
return array[randomInteger(0, array.length - 1)];
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=chance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"chance.js","sourceRoot":"","sources":["../src/chance.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAC,cAAc,EAAC,MAAM,sBAAsB,CAAC;AAEpD,MAAM,UAAU,aAAa,CAAC,GAAW,EAAE,GAAW;IACpD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC;AAC3D,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAW,EAAE,GAAW;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC;IACpD,OAAO,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,GAAG,CAAC,GAAG,GAAG,CAAC,CAAC,8BAA8B;AAC1E,CAAC;AAED,MAAM,UAAU,MAAM,CAAC,aAAqB,EAAE,EAAE,MAAc,CAAC;IAC7D,OAAO,aAAa,CAAC,CAAC,EAAE,GAAG,CAAC,IAAI,eAAe,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,EAAE,GAAG,CAAC,CAAC,CAAC;AAC7E,CAAC;AAED,MAAM,UAAU,YAAY,CAC1B,cAAsB,EACtB,eAAuB;IAEvB,OAAO,cAAc,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,cAAc,EAAE,eAAe,CAAC,CAAE,CAAC;AAC3E,CAAC;AAED,MAAM,UAAU,MAAM,CAAI,KAAU;IAClC,OAAO,KAAK,CAAC,aAAa,CAAC,CAAC,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC;AACnD,CAAC"}
|
package/dist/clamp.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clamp.d.ts","sourceRoot":"","sources":["../src/clamp.ts"],"names":[],"mappings":"AAAA,wBAAgB,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAErE;AAED,wBAAgB,eAAe,CAAC,UAAU,EAAE,MAAM,UAEjD;AAID,wBAAgB,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,GAAG,SAAI,UAExD"}
|
package/dist/clamp.js
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export function clamp(value, min, max) {
|
|
2
|
+
return Math.min(Math.max(value, min), max);
|
|
3
|
+
}
|
|
4
|
+
export function clampLikelihood(likelihood) {
|
|
5
|
+
return clamp(Math.round(likelihood), 0, 100);
|
|
6
|
+
}
|
|
7
|
+
const MAX_POINT = 100;
|
|
8
|
+
export function clampAttribute(attribute, min = 1) {
|
|
9
|
+
return clamp(Math.round(attribute), min, MAX_POINT);
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=clamp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clamp.js","sourceRoot":"","sources":["../src/clamp.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,KAAK,CAAC,KAAa,EAAE,GAAW,EAAE,GAAW;IACzD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,CAAC,EAAE,GAAG,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,UAAkB;IAC9C,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC;AACjD,CAAC;AAED,MAAM,SAAS,GAAG,GAAG,CAAA;AAErB,MAAM,UAAU,cAAc,CAAC,SAAiB,EAAE,GAAG,GAAG,CAAC;IACrD,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,EAAE,GAAG,EAAE,SAAS,CAAC,CAAC;AACxD,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAA"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,UAAU,CAAC;AACzB,cAAc,SAAS,CAAA"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* https://trekhleb.medium.com/weighted-random-in-javascript-4748ab3a1500
|
|
3
|
+
* For example:
|
|
4
|
+
* - items = ['banana', 'orange', 'apple']
|
|
5
|
+
* - weights = [0, 0.2, 0.8]
|
|
6
|
+
* - weightedSample(items, weights) in 80% of cases will return 'apple', in 20% of cases will return
|
|
7
|
+
* 'orange' and it may return banana too even though the weight is 0
|
|
8
|
+
*
|
|
9
|
+
* Item with a -1 weight will nbe ignored.
|
|
10
|
+
* @param items
|
|
11
|
+
* @param weights
|
|
12
|
+
*/
|
|
13
|
+
export declare function weightedSample<T>(items: T[], weights: number[]): T;
|
|
14
|
+
export declare function weightedSampleSize<T>(items: T[], weights: number[], size: number): T[];
|
|
15
|
+
//# sourceMappingURL=weighted-sample.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weighted-sample.d.ts","sourceRoot":"","sources":["../src/weighted-sample.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC5B,KAAK,EAAE,CAAC,EAAE,EACV,OAAO,EAAE,MAAM,EAAE,GAClB,CAAC,CA2BH;AAED,wBAAgB,kBAAkB,CAAC,CAAC,EAChC,KAAK,EAAE,CAAC,EAAE,EACV,OAAO,EAAE,MAAM,EAAE,EACjB,IAAI,EAAE,MAAM,GACb,CAAC,EAAE,CAkCL"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* https://trekhleb.medium.com/weighted-random-in-javascript-4748ab3a1500
|
|
3
|
+
* For example:
|
|
4
|
+
* - items = ['banana', 'orange', 'apple']
|
|
5
|
+
* - weights = [0, 0.2, 0.8]
|
|
6
|
+
* - weightedSample(items, weights) in 80% of cases will return 'apple', in 20% of cases will return
|
|
7
|
+
* 'orange' and it may return banana too even though the weight is 0
|
|
8
|
+
*
|
|
9
|
+
* Item with a -1 weight will nbe ignored.
|
|
10
|
+
* @param items
|
|
11
|
+
* @param weights
|
|
12
|
+
*/
|
|
13
|
+
export function weightedSample(items, weights) {
|
|
14
|
+
if (items.length !== weights.length) {
|
|
15
|
+
throw new Error("Items and weights must be of the same size");
|
|
16
|
+
}
|
|
17
|
+
if (items.length === 0) {
|
|
18
|
+
throw new Error("Items must not be empty");
|
|
19
|
+
}
|
|
20
|
+
const cumulativeWeights = [];
|
|
21
|
+
for (let i = 0; i < weights.length; i += 1) {
|
|
22
|
+
const prevCumulative = cumulativeWeights[i - 1] ?? 0;
|
|
23
|
+
cumulativeWeights[i] = (weights[i] ?? 0) + prevCumulative;
|
|
24
|
+
}
|
|
25
|
+
// Use '!' or a fallback because we've already checked items.length > 0
|
|
26
|
+
const maxCumulativeWeight = cumulativeWeights[cumulativeWeights.length - 1];
|
|
27
|
+
const randomNumber = maxCumulativeWeight * Math.random();
|
|
28
|
+
for (let itemIndex = 0; itemIndex < items.length; itemIndex += 1) {
|
|
29
|
+
if (cumulativeWeights[itemIndex] >= randomNumber) {
|
|
30
|
+
return items[itemIndex];
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
// Fallback for TS satisfaction, though mathematically unreachable
|
|
34
|
+
return items[items.length - 1];
|
|
35
|
+
}
|
|
36
|
+
export function weightedSampleSize(items, weights, size) {
|
|
37
|
+
// 1. Validation
|
|
38
|
+
if (items.length !== weights.length) {
|
|
39
|
+
throw new Error("Items and weights must be of the same size");
|
|
40
|
+
}
|
|
41
|
+
if (size > items.length) {
|
|
42
|
+
throw new Error("Sample size cannot be larger than the number of items");
|
|
43
|
+
}
|
|
44
|
+
// 2. Setup a pool to track remaining items and weights
|
|
45
|
+
const result = [];
|
|
46
|
+
const pool = items.map((item, i) => ({
|
|
47
|
+
item,
|
|
48
|
+
weight: weights[i] ?? 0 // Handle potential undefined/null weights
|
|
49
|
+
}));
|
|
50
|
+
// 3. Selection Loop
|
|
51
|
+
for (let i = 0; i < size; i++) {
|
|
52
|
+
const totalWeight = pool.reduce((sum, p) => sum + p.weight, 0);
|
|
53
|
+
let randomNumber = Math.random() * totalWeight;
|
|
54
|
+
for (let j = 0; j < pool.length; j++) {
|
|
55
|
+
const entry = pool[j]; // Safe because we are within pool.length
|
|
56
|
+
randomNumber -= entry.weight;
|
|
57
|
+
if (randomNumber <= 0 || j === pool.length - 1) {
|
|
58
|
+
result.push(entry.item);
|
|
59
|
+
pool.splice(j, 1); // Remove to ensure uniqueness
|
|
60
|
+
break;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return result;
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=weighted-sample.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"weighted-sample.js","sourceRoot":"","sources":["../src/weighted-sample.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@simcups/chance-utils",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "Slim utility for weighted sampling, chance logic, and math clamping.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./dist/index.js"
|
|
10
|
+
},
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "tsc",
|
|
13
|
+
"prepare": "npm run build",
|
|
14
|
+
"prepublishOnly": "npm run build",
|
|
15
|
+
"clean": "rm -rf dist"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"author": "kaichunglau <laukaichung@simcups.com>",
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"typescript": "^6.0.2"
|
|
24
|
+
}
|
|
25
|
+
}
|