minesweeper/src/main/js/Common.ts

105 lines
3.5 KiB
TypeScript

// @ts-ignore
import * as random from "fast-random";
/**
* Shuffles the given array in-place.
*
* @param array the array to shuffle
* @param seed the seed for the random number generator
* @returns the array that was given to this function to shuffle
*/
export function shuffleArrayInPlace(array: any[], seed: number | undefined = undefined): any[] {
const rng = random(seed);
for (let i = array.length - 1; i > 0; i--) {
const j = rng.nextInt() % (i + 1);
[array[i], array[j]] = [array[j], array[i]];
}
return array;
}
/**
* Slices `array` into chunks of `chunkSize` elements each.
*
* If `array` does not contain a multiple of `chunkSize` elements, the last chunk will contain fewer elements.
*
* @param array the array to chunkify
* @param chunkSize the size of each chunk
* @returns an array of the extracted chunks
*/
export function chunkifyArray(array: any[], chunkSize: number): any[] {
const chunks = [];
for (let i = 0; i < array.length; i += chunkSize)
chunks.push(array.slice(i, i + chunkSize));
return chunks;
}
/**
* Creates an array of `size` consecutive integers starting at `startAt`.
*
* Taken from https://stackoverflow.com/a/10050831 (CC BY-SA 4.0).
*
* @param length the number of consecutive integers to put in the array
* @param beginAt the first integer to return
* @returns the array of consecutive integers
*/
export function range(length: number, beginAt: number = 0): number[] {
return [...Array(length).keys()].map(i => i + beginAt);
}
/**
* Waits for FontAwesome to have loaded and then invokes the callback.
*
* Taken from https://stackoverflow.com/a/35572620/ (CC BY-SA 3.0).
*
* @param callback the function to invoke once the font has loaded
* @param timeout the maximum time in milliseconds to wait for the font to load
*/
export function waitForForkAwesome(callback: () => void, timeout: number | undefined = undefined): void {
const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d")!;
const fontSize = 36;
const testCharacter = "\uF047";
const targetPixelCount = 500;
const ccw = canvas.width = fontSize * 1.5;
const cch = canvas.height = fontSize * 1.5;
ctx.font = `${fontSize}px ForkAwesome`;
ctx.textAlign = "center";
ctx.textBaseline = "middle";
const startTime = performance.now();
const failTime = timeout === undefined ? undefined : startTime + timeout;
requestAnimationFrame(fontOnload);
/**
* Repeatedly invokes itself until the font has loaded or the timeout has been reached.
*
* @param time the time in milliseconds at which this function is invoked
*/
function fontOnload(time: number): void {
const currentCount = getPixelCount();
if (failTime !== undefined && time > failTime) alert(`ForkAwesome failed to load after ${timeout}ms.`);
else if (currentCount < targetPixelCount) requestAnimationFrame(fontOnload);
else callback();
}
/**
* Draws a character in the canvas and returns the number of pixels that have been drawn.
*
* @returns the number of pixels that have been drawn
*/
function getPixelCount(): number {
ctx.clearRect(0, 0, ccw, cch);
ctx.fillText(testCharacter, ccw / 2, cch / 2);
const data = ctx.getImageData(0, 0, ccw, cch).data;
let count = 0;
for (let i = 3; i < data.length; i += 4)
if (data[i] > 10) count++;
return count;
}
}