Skip to content

Commit

Permalink
feat(tools): add new methods to random and fix noise generation
Browse files Browse the repository at this point in the history
  • Loading branch information
ricardomatias committed Sep 28, 2022
1 parent 984aa21 commit c9df92b
Show file tree
Hide file tree
Showing 2 changed files with 139 additions and 62 deletions.
62 changes: 43 additions & 19 deletions lib/tools/random.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
/* eslint-disable @typescript-eslint/ban-ts-comment */
/* eslint-disable no-invalid-this */
/* eslint-disable no-var, new-cap */
/* eslint-disable @typescript-eslint/ban-ts-comment */
import Alea from 'alea';
import SimplexNoise from 'simplex-noise';
import { NoiseFunction2D, createNoise2D } from 'simplex-noise';
import { PlayaError } from '../utils';

const INITIAL_SEED = 'PLAYA';
const INITIAL_X = 0;
const INITIAL_Y = 999;
const INITIAL_INCREMENT = 10;

/**
* It uses Simplex Noise in order for the Random numbers to follow a "more natural" progression.
Expand All @@ -25,17 +25,17 @@ const INITIAL_Y = 999;
export class Random {
private static instance: Random;
#x = INITIAL_X;
#y = INITIAL_Y;
#prevX = 0;
#prevY = 0;
/*@ts-expect-error */
// @ts-ignore
#rng = new Alea(INITIAL_SEED);
#simplex: SimplexNoise = new SimplexNoise(this.#rng);
#simplex: NoiseFunction2D = createNoise2D(this.#rng);
#seed: string | number = INITIAL_SEED;
#prevSeed: string | number = INITIAL_SEED;
#prevIncrement = 0;
#state?: [number, number, number, number];
#seedCounter = 0;

public increment = 10;
public increment = INITIAL_INCREMENT;

public static getInstance(): Random {
if (!Random.instance) {
Expand Down Expand Up @@ -83,9 +83,10 @@ export class Random {
push(): void {
this.#state = this.#rng.exportState();
this.#prevX = this.#x;
this.#prevY = this.#y;
this.#prevSeed = this.#seed;
this.#prevIncrement = this.increment;

this.setSeed(this.seed, this.increment);
this.setSeed(this.#seed, this.increment);
}

/**
Expand All @@ -94,17 +95,22 @@ export class Random {
* @memberof Tools.Random
*/
pop(): void {
this.#seed = this.#prevSeed;
this.increment = this.#prevIncrement;
this.#x = this.#prevX;
this.#y = this.#prevY;
this.#prevX = 0;
this.#prevY = 0;

if (this.#state) {
// @ts-ignore
this.#rng.importState(this.#state);
this.#simplex = new SimplexNoise(this.#rng);
// this.#simplex = createNoise2D(this.#rng);
} else {
throw new PlayaError('Random', 'Must use .push() before .pop()');
}

this.#prevX = 0;
this.#state = undefined;
this.#prevIncrement = 0;
this.#prevSeed = INITIAL_SEED;
}

/**
Expand All @@ -117,12 +123,31 @@ export class Random {
*/
setSeed = (seed: string | number, increment: number = this.increment): void => {
this.#x = 0;
this.#y = 999;
this.#seed = seed;
this.increment = increment;
/*@ts-ignore */
// @ts-ignore
this.#rng = new Alea(seed);
this.#simplex = new SimplexNoise(this.#rng);
this.#simplex = createNoise2D(this.#rng);
};

/**
* Creates a fresh seed based
* @function freshSeed
* @memberof Tools.Random
*
* @param {Number} increment
*/
freshSeed = (increment: number = this.increment): void => {
this.setSeed(Math.floor(Math.random() * 9999999).toString(), increment);
};

/**
* Resets to initial state with the defaults
* @function reset
* @memberof Tools.Random
*/
reset = () => {
this.setSeed(INITIAL_SEED, INITIAL_INCREMENT);
};

/**
Expand Down Expand Up @@ -153,9 +178,8 @@ export class Random {
*/
float = (max = 1.0, min = 0.0): number => {
this.#x += this.increment;
this.#y += this.increment;

const value = (this.#simplex.noise2D(this.#x, this.#y) + 1) / 2;
const value = (this.#simplex(this.#x, 1.0) + 1) / 2;
const result = min + value * (max - min);

return result;
Expand Down
139 changes: 96 additions & 43 deletions test/tools/random.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import random, { Random } from '../../lib/tools/random';
import { mapRepeat } from '../../lib/tools/map-repeat';

describe('A Random test suite', () => {
beforeEach(() => random.reset());

it('should return singleton', () => {
const result = mapRepeat(10, () => {
random.setSeed('test');
Expand All @@ -15,43 +17,87 @@ describe('A Random test suite', () => {
it('should create new random int', () => {
random.setSeed('test');

const results = mapRepeat(10, () => random.int(10, 5));
const results = mapRepeat(10, () => random.int(20, 10));

expect(results.filter((n) => n >= 5 && n <= 10)).toHaveLength(10);
expect(results.filter((n) => n >= 10 && n <= 20)).toHaveLength(10);
expect(results).toMatchInlineSnapshot(`
Array [
7,
6,
6,
7,
5,
6,
6,
8,
8,
8,
[
15,
10,
12,
15,
17,
15,
15,
17,
15,
15,
]
`);
});

it('should create new random int small increment', () => {
random.setSeed('test', 0.1);

const results = mapRepeat(10, () => random.int(20, 10));

expect(results.filter((n) => n >= 10 && n <= 20)).toHaveLength(10);
expect(results).toMatchInlineSnapshot(`
[
10,
11,
11,
12,
12,
13,
14,
15,
16,
17,
]
`);
});

it('should create new random int large increment', () => {
random.setSeed('test', 100);

const results = mapRepeat(10, () => random.int(20, 10));

expect(results.filter((n) => n >= 10 && n <= 20)).toHaveLength(10);
expect(results).toMatchInlineSnapshot(`
[
15,
17,
13,
17,
18,
15,
14,
19,
13,
16,
]
`);
});

it('should create new random float', () => {
random.setSeed('test');
random.setSeed('test', 10);

const results = mapRepeat(10, () => random.float(10, 5));

expect(results.filter((n) => n >= 5 && n <= 10)).toHaveLength(10);
expect(results.map((n) => n.toFixed(3))).toMatchInlineSnapshot(`
Array [
"7.373",
"6.428",
"6.259",
"7.137",
"5.220",
"6.585",
"6.335",
"7.507",
"7.824",
"8.275",
[
"7.335",
"5.325",
"6.269",
"7.544",
"8.494",
"7.606",
"7.654",
"8.273",
"7.425",
"7.697",
]
`);
});
Expand All @@ -62,48 +108,55 @@ describe('A Random test suite', () => {
expect(rnd.boolean()).toBe(true);
});

it('should return a fresh seed', () => {
const rnd = new Random();
rnd.setSeed('test');

rnd.freshSeed();

expect(rnd.seed).not.toBe('test');
});

it('should keep state', () => {
random.setSeed('test');

expect(random.int(5)).toEqual(2);
expect(random.int(10)).toEqual(3);
expect(random.int(10)).toEqual(0);
expect(random.int(100)).toEqual(25);

random.push();

expect(random.int(5)).toEqual(2);
expect(random.int(10)).toEqual(3);
expect(random.int(10)).toEqual(0);
expect(random.int(100)).toEqual(25);

expect(random.int(1000)).toEqual(427);
expect(random.int(10000)).toEqual(5089);
expect(random.int(10000)).toEqual(6989);

random.pop();

expect(random.int(1000)).toEqual(427);
expect(random.int(10000)).toEqual(5089);
expect(random.int(10000)).toEqual(6989);
});

it('should not keep state', () => {
random.setSeed('test');

expect(random.int(5)).toEqual(2);
expect(random.int(10)).toEqual(3);
expect(random.int(100)).toEqual(25);
expect(random.int(9999)).toEqual(4669);
expect(random.int(9999)).toEqual(650);
expect(random.int(9999)).toEqual(2538);

random.setSeed('test-2');
random.push();
random.setSeed('test22222');

expect(random.int(5)).not.toEqual(2);
expect(random.int(10)).not.toEqual(3);
expect(random.int(100)).not.toEqual(25);

expect(random.int(1000)).not.toEqual(427);
expect(random.int(9999)).toEqual(5330);
expect(random.int(9999)).toEqual(4669);
expect(random.int(9999)).toEqual(5569);

random.pop();

random.setSeed('test');

expect(random.int(5)).toEqual(2);
expect(random.int(10)).toEqual(3);
expect(random.int(100)).toEqual(25);
expect(random.int(9999)).toEqual(5000);
expect(random.int(9999)).toEqual(2551);
expect(random.int(9999)).toEqual(2557);
});
});

0 comments on commit c9df92b

Please sign in to comment.