summary refs log tree commit diff
path: root/src/extensions/Random.ts
blob: 212e1c9aaf6c9c0332656f9aa3f3ea55d47c7f2c (plain) (blame)
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
80
81
82
83
84
85
86
87
88
89
90
91
92
/*
	Spacebar: A FOSS re-implementation and extension of the Discord.com backend.
	Copyright (C) 2026 Spacebar and Spacebar Contributors

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU Affero General Public License as published
	by the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU Affero General Public License for more details.

	You should have received a copy of the GNU Affero General Public License
	along with this program.  If not, see <https://www.gnu.org/licenses/>.
*/

// Inspired by dotnet: https://learn.microsoft.com/en-us/dotnet/api/system.random?view=net-9.0#methods
export class Random {
    public static nextInt(min?: number, max?: number): number {
        if (min === undefined && max === undefined) {
            // Next()
            return Math.floor(Math.random() * Number.MAX_SAFE_INTEGER);
        } else if (max === undefined) {
            // Next(Int32)
            if (min! <= 0) throw new RangeError("min must be greater than 0");
            return Math.floor(Math.random() * min!);
        } else {
            // Next(Int32, Int32)
            if (min! >= max!) throw new RangeError("min must be less than max");
            return Math.floor(Math.random() * (max! - min!)) + min!;
        }
    }

    public static nextDouble(min?: number, max?: number): number {
        if (min === undefined && max === undefined) {
            // NextDouble()
            return Math.random();
        } else if (max === undefined) {
            // NextDouble(Double)
            if (min! <= 0) throw new RangeError("min must be greater than 0");
            return Math.random() * min!;
        } else {
            // NextDouble(Double, Double)
            if (min! >= max!) throw new RangeError("min must be less than max");
            return Math.random() * (max! - min!) + min!;
        }
    }

    public static nextBytes(count: number): Uint8Array {
        if (count <= 0) throw new RangeError("count must be greater than 0");
        const arr = new Uint8Array(count);
        for (let i = 0; i < count; i++) {
            arr[i] = Math.floor(Math.random() * 256);
        }
        return arr;
    }

    public static nextBytesArray(count: number) {
        if (count <= 0) throw new RangeError("count must be greater than 0");
        const arr = [];
        for (let i = 0; i < count; i++) {
            arr.push(Math.floor(Math.random() * 256));
        }
        return arr;
    }

    public static getItems<T>(items: T[], count: number): T[] {
        if (count <= 0) throw new RangeError("count must be greater than 0");
        if (count >= items.length) return this.shuffle(items);
        const usedIndices = new Set<number>();
        const result: T[] = [];
        while (result.length < count && usedIndices.size < items.length) {
            const index = Math.floor(Math.random() * items.length);
            if (!usedIndices.has(index)) {
                usedIndices.add(index);
                result.push(items[index]);
            }
        }
        return result;
    }

    public static shuffle<T>(items: T[]): T[] {
        const array = [...items];
        for (let i = array.length - 1; i > 0; i--) {
            const j = Math.floor(Math.random() * (i + 1));
            [array[i], array[j]] = [array[j], array[i]];
        }
        return array;
    }
}