2019-09-06 03:54:26 +00:00
|
|
|
import { assert } from "../core/util/Debug";
|
2019-12-16 21:50:07 +00:00
|
|
|
import { clamp } from "../core/util/Math";
|
2019-09-06 03:54:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* The name of the patterns
|
|
|
|
*/
|
2020-03-02 05:11:27 +00:00
|
|
|
export type PatternName = "up" | "down" | "upDown" | "downUp" | "alternateUp" | "alternateDown" | "random" | "randomOnce" | "randomWalk";
|
2019-09-06 03:54:26 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Start at the first value and go up to the last
|
|
|
|
*/
|
2022-01-05 05:12:40 +00:00
|
|
|
function* upPatternGen<T>(numValues: number): IterableIterator<number> {
|
2019-09-06 03:54:26 +00:00
|
|
|
let index = 0;
|
2022-01-05 05:12:40 +00:00
|
|
|
while (index < numValues) {
|
|
|
|
index = clamp(index, 0, numValues - 1);
|
|
|
|
yield index;
|
2019-09-06 03:54:26 +00:00
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Start at the last value and go down to 0
|
|
|
|
*/
|
2022-01-05 05:12:40 +00:00
|
|
|
function* downPatternGen<T>(numValues: number): IterableIterator<number> {
|
|
|
|
let index = numValues - 1;
|
2019-09-06 03:54:26 +00:00
|
|
|
while (index >= 0) {
|
2022-01-05 05:12:40 +00:00
|
|
|
index = clamp(index, 0, numValues - 1);
|
|
|
|
yield index;
|
2019-09-06 03:54:26 +00:00
|
|
|
index--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Infinitely yield the generator
|
|
|
|
*/
|
2022-01-05 05:12:40 +00:00
|
|
|
function* infiniteGen<T>(numValues: number, gen: typeof upPatternGen): IterableIterator<number> {
|
2019-09-06 03:54:26 +00:00
|
|
|
while (true) {
|
2022-01-05 05:12:40 +00:00
|
|
|
yield* gen(numValues);
|
2019-09-06 03:54:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Alternate between two generators
|
|
|
|
*/
|
2022-01-05 05:12:40 +00:00
|
|
|
function* alternatingGenerator<T>(numValues: number, directionUp: boolean): IterableIterator<number> {
|
|
|
|
let index = directionUp ? 0 : numValues - 1;
|
2019-09-06 03:54:26 +00:00
|
|
|
while (true) {
|
2022-01-05 05:12:40 +00:00
|
|
|
index = clamp(index, 0, numValues - 1);
|
|
|
|
yield index;
|
2019-09-06 03:54:26 +00:00
|
|
|
if (directionUp) {
|
|
|
|
index++;
|
2022-01-05 05:12:40 +00:00
|
|
|
if (index >= numValues - 1) {
|
2019-09-06 03:54:26 +00:00
|
|
|
directionUp = false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
index--;
|
|
|
|
if (index <= 0) {
|
|
|
|
directionUp = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Starting from the bottom move up 2, down 1
|
|
|
|
*/
|
2022-01-05 05:12:40 +00:00
|
|
|
function* jumpUp<T>(numValues: number): IterableIterator<number> {
|
2019-09-06 03:54:26 +00:00
|
|
|
let index = 0;
|
|
|
|
let stepIndex = 0;
|
2022-01-05 05:12:40 +00:00
|
|
|
while (index < numValues) {
|
|
|
|
index = clamp(index, 0, numValues - 1);
|
|
|
|
yield index;
|
2019-09-06 03:54:26 +00:00
|
|
|
stepIndex++;
|
|
|
|
index += (stepIndex % 2 ? 2 : -1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Starting from the top move down 2, up 1
|
|
|
|
*/
|
2022-01-05 05:12:40 +00:00
|
|
|
function* jumpDown<T>(numValues: number): IterableIterator<number> {
|
|
|
|
let index = numValues - 1;
|
2019-09-06 03:54:26 +00:00
|
|
|
let stepIndex = 0;
|
|
|
|
while (index >= 0) {
|
2022-01-05 05:12:40 +00:00
|
|
|
index = clamp(index, 0, numValues - 1);
|
|
|
|
yield index;
|
2019-09-06 03:54:26 +00:00
|
|
|
stepIndex++;
|
|
|
|
index += (stepIndex % 2 ? -2 : 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Choose a random index each time
|
|
|
|
*/
|
2022-01-05 05:12:40 +00:00
|
|
|
function* randomGen<T>(numValues: number): IterableIterator<number> {
|
2019-09-06 03:54:26 +00:00
|
|
|
while (true) {
|
2022-01-05 05:12:40 +00:00
|
|
|
const randomIndex = Math.floor(Math.random() * numValues);
|
|
|
|
yield randomIndex;
|
2019-09-06 03:54:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Randomly go through all of the values once before choosing a new random order
|
|
|
|
*/
|
2022-01-05 05:12:40 +00:00
|
|
|
function* randomOnce<T>(numValues: number): IterableIterator<number> {
|
2019-09-06 03:54:26 +00:00
|
|
|
// create an array of indices
|
|
|
|
const copy: number[] = [];
|
2022-01-05 05:12:40 +00:00
|
|
|
for (let i = 0; i < numValues; i++) {
|
2019-09-06 03:54:26 +00:00
|
|
|
copy.push(i);
|
|
|
|
}
|
|
|
|
while (copy.length > 0) {
|
|
|
|
// random choose an index, and then remove it so it's not chosen again
|
|
|
|
const randVal = copy.splice(Math.floor(copy.length * Math.random()), 1);
|
2022-01-05 05:12:40 +00:00
|
|
|
const index = clamp(randVal[0], 0, numValues - 1);
|
|
|
|
yield index;
|
2019-09-06 03:54:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-03-02 05:11:27 +00:00
|
|
|
/**
|
|
|
|
* Randomly choose to walk up or down 1 index in the values array
|
|
|
|
*/
|
2022-01-05 05:12:40 +00:00
|
|
|
function* randomWalk<T>(numValues: number): IterableIterator<number> {
|
2020-03-08 16:10:39 +00:00
|
|
|
// randomly choose a starting index in the values array
|
2022-01-05 05:12:40 +00:00
|
|
|
let index = Math.floor(Math.random() * numValues);
|
2020-03-02 05:11:27 +00:00
|
|
|
while (true) {
|
2020-03-08 16:10:39 +00:00
|
|
|
if (index === 0) {
|
|
|
|
index++; // at bottom of array, so force upward step
|
2022-01-05 05:12:40 +00:00
|
|
|
} else if (index === numValues - 1) {
|
2020-03-08 16:10:39 +00:00
|
|
|
index--; // at top of array, so force downward step
|
|
|
|
} else if (Math.random() < 0.5) { // else choose random downward or upward step
|
2020-03-02 05:11:27 +00:00
|
|
|
index--;
|
|
|
|
} else {
|
|
|
|
index++;
|
|
|
|
}
|
2022-01-05 05:12:40 +00:00
|
|
|
yield index;
|
2020-03-02 05:11:27 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-09-06 03:54:26 +00:00
|
|
|
/**
|
2022-01-05 05:12:40 +00:00
|
|
|
* PatternGenerator returns a generator which will yield numbers between 0 and numValues
|
|
|
|
* according to the passed in pattern that can be used as indexes into an array of size numValues.
|
|
|
|
* @param numValues The size of the array to emit indexes for
|
2019-09-06 03:54:26 +00:00
|
|
|
* @param pattern The name of the pattern use when iterating over
|
2019-11-07 19:39:28 +00:00
|
|
|
* @param index Where to start in the offset of the values array
|
2019-09-06 03:54:26 +00:00
|
|
|
*/
|
2022-01-05 05:12:40 +00:00
|
|
|
export function* PatternGenerator(numValues: number, pattern: PatternName = "up", index = 0): Iterator<number> {
|
2019-09-06 03:54:26 +00:00
|
|
|
// safeguards
|
2022-01-05 05:12:40 +00:00
|
|
|
assert(numValues >= 1, "The number of values must be at least one");
|
2019-09-06 03:54:26 +00:00
|
|
|
switch (pattern) {
|
|
|
|
case "up" :
|
2022-01-05 05:12:40 +00:00
|
|
|
yield* infiniteGen(numValues, upPatternGen);
|
2019-09-06 03:54:26 +00:00
|
|
|
case "down" :
|
2022-01-05 05:12:40 +00:00
|
|
|
yield* infiniteGen(numValues, downPatternGen);
|
2019-09-06 03:54:26 +00:00
|
|
|
case "upDown" :
|
2022-01-05 05:12:40 +00:00
|
|
|
yield* alternatingGenerator(numValues, true);
|
2019-09-06 03:54:26 +00:00
|
|
|
case "downUp" :
|
2022-01-05 05:12:40 +00:00
|
|
|
yield* alternatingGenerator(numValues, false);
|
2019-09-06 03:54:26 +00:00
|
|
|
case "alternateUp":
|
2022-01-05 05:12:40 +00:00
|
|
|
yield* infiniteGen(numValues, jumpUp);
|
2019-09-06 03:54:26 +00:00
|
|
|
case "alternateDown":
|
2022-01-05 05:12:40 +00:00
|
|
|
yield* infiniteGen(numValues, jumpDown);
|
2019-09-06 03:54:26 +00:00
|
|
|
case "random":
|
2022-01-05 05:12:40 +00:00
|
|
|
yield* randomGen(numValues);
|
2019-09-06 03:54:26 +00:00
|
|
|
case "randomOnce":
|
2022-01-05 05:12:40 +00:00
|
|
|
yield* infiniteGen(numValues, randomOnce);
|
2020-03-08 16:10:39 +00:00
|
|
|
case "randomWalk":
|
2022-01-05 05:12:40 +00:00
|
|
|
yield* randomWalk(numValues);
|
2019-09-06 03:54:26 +00:00
|
|
|
}
|
|
|
|
}
|