improved perfomance of PseudoRandom (#933)

## Description:
Added  XorShift algo for better random number generation
## Please complete the following:

- [x] I have added screenshots for all UI updates
- [ ] I have added relevant tests to the test directory
- [x] I process any text displayed to the user through translateText()
and i've added it to the en.json file
- [x] I confirm I have thoroughly tested these changes and take full
responsibility for any bugs introduced
- [x] I understand that submitting code with bugs that could have been
caught through manual testing blocks releases and new features for all
contributors

## Please put your Discord username so you can be contacted if a bug or
regression is found:

@qqkedsi

![Screenshot from 2025-05-29
00-25-20](https://github.com/user-attachments/assets/7e748c7f-3bc2-4275-8ffd-9adf3a224064)

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
This commit is contained in:
falc
2025-05-30 00:16:35 +02:00
committed by GitHub
parent 32d746768e
commit 9471fdaf1f
+29 -11
View File
@@ -9,6 +9,9 @@ export class PseudoRandom {
private c: number = 12345;
private state: number;
private static readonly POW36_8 = Math.pow(36, 8); // Pre-compute 36^8
private static readonly INV_2_32 = 1 / 4294967296; // 1 / 2^32 for float conversion
constructor(seed: number) {
// Initialize the XorShift state with seed
this.state0 = seed | 0; // Force to 32-bit integer with bitwise OR
@@ -48,6 +51,13 @@ export class PseudoRandom {
return (this.state0 + this.state1) | 0;
}
/**
* Optimized version that directly returns unsigned 32-bit integer
*/
private _nextUInt32(): number {
return this._nextIntInternal() >>> 0;
}
/**
* Generates the next pseudorandom number.
* @returns A number between 0 (inclusive) and 1 (exclusive).
@@ -55,7 +65,7 @@ export class PseudoRandom {
next(): number {
// Get a 32-bit integer and convert to [0,1) range
// Using >>> 0 to get unsigned interpretation (positive number)
const int = this._nextIntInternal() >>> 0;
const int = this._nextUInt32();
// Update the state variable to maintain compatibility with original interface
this.state = int % this.m;
@@ -64,25 +74,33 @@ export class PseudoRandom {
return this.state / this.m;
}
/**
* Optimized version for internal use - directly converts to [0,1) without state update
*/
private _nextFloat(): number {
return this._nextUInt32() * PseudoRandom.INV_2_32;
}
/**
* Generates a random integer between min (inclusive) and max (exclusive).
*/
nextInt(min: number, max: number): number {
return Math.floor(this.next() * (max - min) + min);
// keep max exclusive, min inclusive round down to get an int
return Math.floor(this._nextFloat() * (max - min)) + min;
}
/**
* Generates a random float between min (inclusive) and max (exclusive).
*/
nextFloat(min: number, max: number): number {
return this.next() * (max - min) + min;
return this._nextFloat() * (max - min) + min;
}
/**
* Generates a random ID (8 characters, alphanumeric).
*/
nextID(): string {
return this.nextInt(0, Math.pow(36, 8)) // 36^8 possibilities
return Math.floor(this._nextFloat() * PseudoRandom.POW36_8) // 36^8 possibilities
.toString(36) // Convert to base36 (0-9 and a-z)
.padStart(8, "0"); // Ensure 8 chars by padding with zeros
}
@@ -94,25 +112,25 @@ export class PseudoRandom {
if (arr.length === 0) {
throw new Error("array must not be empty");
}
return arr[this.nextInt(0, arr.length)];
return arr[Math.floor(this._nextFloat() * arr.length)];
}
/**
* Returns true with probability 1/odds.
*/
chance(odds: number): boolean {
return this.nextInt(0, odds) === 0;
return Math.floor(this._nextFloat() * odds) === 0;
}
/**
* Returns a shuffled copy of the array using Fisher-Yates algorithm.
*/
shuffleArray<T>(array: T[]): T[] {
for (let i = array.length - 1; i >= 0; i--) {
const j = this.nextInt(0, i + 1);
[array[i], array[j]] = [array[j], array[i]];
const result = [...array];
for (let i = result.length - 1; i >= 0; i--) {
const j = Math.floor(this._nextFloat() * (i + 1));
[result[i], result[j]] = [result[j], result[i]];
}
return array;
return result;
}
}