-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmod.ts
79 lines (68 loc) · 2.15 KB
/
mod.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
interface IRandomMixElement<T> {
obj: T;
weight: number;
}
export class RandomMix<T> {
universe: IRandomMixElement<T>[] = [];
randomMix: IRandomMixElement<T>[] = [];
currentElementIndex: number = 0;
elementsToSelectFrom: IRandomMixElement<T>[] = [];
constructor(universe: IRandomMixElement<T>[]) {
universe.forEach((element) => {
if (element.weight < 0) {
throw new Error("Weights can't be negative.");
}
});
this.universe = shallowCopy(universe);
this.randomMix = [];
this.currentElementIndex = 0;
this.elementsToSelectFrom = shallowCopy(universe);
this.injectNewElementAtEndOfRandomMix();
}
injectNewElementAtEndOfRandomMix(): void {
if (this.getNumberOfElementsToSelectFrom() === 0) {
return;
}
const randomElementIndex = this.getRandomElementIndex();
this.randomMix.push(this.elementsToSelectFrom[randomElementIndex]);
this.elementsToSelectFrom.splice(randomElementIndex, 1);
}
getRandomElementIndex(): number {
const sumWeights = this.elementsToSelectFrom.reduce(
(sum, element) => sum + element.weight,
0
);
const randomNumberInWeightSumRange = Math.random() * sumWeights;
let curWeightSum = 0;
for (let index = 0; index < this.elementsToSelectFrom.length; index++) {
curWeightSum += this.elementsToSelectFrom[index].weight;
if (curWeightSum > randomNumberInWeightSumRange) {
return index;
}
}
throw new Error("Unreachable code. For-loop will return. Always.");
}
getCurrentElement(): T {
return this.randomMix[this.currentElementIndex]?.obj;
}
getNumberOfElementsToSelectFrom(): number {
return this.elementsToSelectFrom.length;
}
moveToNextRandomMixElement(): void {
if (this.currentElementIndex === this.randomMix.length - 1) {
if (this.getNumberOfElementsToSelectFrom() === 0) {
return;
}
this.injectNewElementAtEndOfRandomMix();
}
this.currentElementIndex++;
}
moveToPreviousRandomMixElement(): void {
if (this.currentElementIndex > 0) {
this.currentElementIndex--;
}
}
}
function shallowCopy(arr: any[]): any[] {
return arr.slice(0);
}