refactor(es modules): modulize utils

This commit is contained in:
Azgaar 2022-06-26 20:44:29 +03:00
parent 12e1c9f334
commit 7ccebec048
54 changed files with 168 additions and 134 deletions

View file

@ -7664,13 +7664,6 @@
<script src="libs/priority-queue.min.js"></script>
<script src="libs/delaunator.min.js"></script>
<script src="utils/commonUtils.js"></script>
<script src="utils/nodeUtils.js"></script>
<script src="utils/probabilityUtils.js"></script>
<script src="utils/stringUtils.js"></script>
<script src="utils/languageUtils.js"></script>
<script src="utils/unitUtils.js?v=1.87.00"></script>
<script src="modules/voronoi.js"></script>
<script src="config/heightmap-templates.js"></script>
<script src="config/precreated-heightmaps.js"></script>

View file

@ -4,6 +4,8 @@ import {layerIsOn} from "./ui/layers";
import {getColors, getRandomColor, getMixedColor} from "/src/utils/colorUtils";
import {getMiddlePoint} from "@/utils/lineUtils";
import {rn, minmax} from "/src/utils/numberUtils";
import {rand, P, each, gauss, ra, rw, generateSeed} from "@/utils/probabilityUtils";
import {round, splitInTwo} from "@/utils/stringUtils";
window.BurgsAndStates = (function () {
const generate = function () {

View file

@ -1,3 +1,5 @@
import {P, rw} from "@/utils/probabilityUtils";
window.COA = (function () {
const tinctures = {
field: {metals: 3, colours: 4, stains: +P(0.03), patterns: 1},

View file

@ -1,6 +1,7 @@
import {TIME} from "/src/config/logging";
import {getColors} from "/src/utils/colorUtils";
import {rn, minmax} from "/src/utils/numberUtils";
import {rand, P, rw, biased} from "@/utils/probabilityUtils";
window.Cultures = (function () {
let cells;

View file

@ -1,5 +1,7 @@
import {findCell} from "/src/utils/graphUtils";
import {rn} from "/src/utils/numberUtils";
import {rand, P, rw} from "@/utils/probabilityUtils";
import {parseTransform} from "@/utils/stringUtils";
// update old .map version to the current one
export function resolveVersionConflicts(version) {

View file

@ -3,6 +3,7 @@ import {findAll, findCell, getPackPolygon, isLand} from "/src/utils/graphUtils";
import {tip, showMainTip, clearMainTip} from "/src/scripts/tooltips";
import {byId} from "/src/utils/shorthands";
import {rn} from "/src/utils/numberUtils";
import {capitalize} from "@/utils/stringUtils";
const $body = insertEditorHtml();
addListeners();

View file

@ -4,6 +4,7 @@ import {byId} from "/src/utils/shorthands";
import {tip, showMainTip, clearMainTip} from "/src/scripts/tooltips";
import {getRandomColor, getMixedColor} from "/src/utils/colorUtils";
import {rn} from "/src/utils/numberUtils";
import {rand, P} from "@/utils/probabilityUtils";
const $body = insertEditorHtml();
addListeners();

View file

@ -1,5 +1,6 @@
import {shouldRegenerateGrid, generateGrid} from "/src/utils/graphUtils";
import {byId} from "/src/utils/shorthands";
import {generateSeed} from "@/utils/probabilityUtils";
const initialSeed = generateSeed();
let graph = getGraph(grid);

View file

@ -1,5 +1,6 @@
import {byId} from "/src/utils/shorthands";
import {tip} from "/src/scripts/tooltips";
import {capitalize} from "@/utils/stringUtils";
appendStyleSheet();
insertHtml();

View file

@ -3,6 +3,7 @@ import {isWater} from "/src/utils/graphUtils";
import {tip} from "/src/scripts/tooltips";
import {byId} from "/src/utils/shorthands";
import {rn} from "/src/utils/numberUtils";
import {capitalize} from "@/utils/stringUtils";
const entitiesMap = {
states: {

View file

@ -1,3 +1,5 @@
import {capitalize} from "@/utils/stringUtils";
const capitalize = text => text.charAt(0).toUpperCase() + text.slice(1);
const format = rawList =>

View file

@ -2,6 +2,7 @@ import {TIME} from "/src/config/logging";
import {createTypedArray} from "/src/utils/arrayUtils";
import {findGridCell} from "/src/utils/graphUtils";
import {byId} from "/src/utils/shorthands";
import {rand, P, getNumberInRange} from "@/utils/probabilityUtils";
window.HeightmapGenerator = (function () {
let grid = null;

View file

@ -1,6 +1,7 @@
import {tip} from "/src/scripts/tooltips";
import {rn} from "/src/utils/numberUtils";
import {ldb} from "@/scripts/indexedDB";
import {ra} from "@/utils/probabilityUtils";
// functions to save project as .map file

View file

@ -2,6 +2,8 @@ import {TIME} from "/src/config/logging";
import {getFriendlyHeight} from "./ui/general";
import {last} from "/src/utils/arrayUtils";
import {rn} from "/src/utils/numberUtils";
import {rand, P, gauss, ra, rw} from "@/utils/probabilityUtils";
import {capitalize} from "@/utils/stringUtils";
window.Markers = (function () {
let config = [];

View file

@ -1,5 +1,6 @@
import {TIME} from "/src/config/logging";
import {rn, minmax} from "/src/utils/numberUtils";
import {rand, gauss, ra} from "@/utils/probabilityUtils";
window.Military = (function () {
const generate = function () {

View file

@ -1,6 +1,8 @@
import {last} from "/src/utils/arrayUtils";
import {locked} from "/src/scripts/options/lock";
import {tip} from "/src/scripts/tooltips";
import {rand, P, ra} from "@/utils/probabilityUtils";
import {capitalize} from "@/utils/stringUtils";
window.Names = (function () {
let chains = [];

View file

@ -1,6 +1,8 @@
import {TIME} from "@/config/logging";
import {clipPoly} from "@/utils/lineUtils";
import {rn} from "@/utils/numberUtils";
import {P} from "@/utils/probabilityUtils";
import {round} from "@/utils/stringUtils";
window.OceanLayers = (function () {
let cells, vertices, pointsN, used;

View file

@ -1,5 +1,6 @@
import {getPackPolygon} from "/src/utils/graphUtils";
import {rn, minmax} from "/src/utils/numberUtils";
import {rand} from "@/utils/probabilityUtils";
window.ReliefIcons = (function () {
const ReliefIcons = function () {

View file

@ -3,6 +3,7 @@ import {findAll} from "/src/utils/graphUtils";
import {unique} from "/src/utils/arrayUtils";
import {getRandomColor, getMixedColor} from "/src/utils/colorUtils";
import {rn} from "/src/utils/numberUtils";
import {rand, P, ra, rw, biased} from "@/utils/probabilityUtils";
window.Religions = (function () {
// name generation approach and relative chance to be selected

View file

@ -1,6 +1,7 @@
import {TIME} from "/src/config/logging";
import {last} from "/src/utils/arrayUtils";
import {rn} from "/src/utils/numberUtils";
import {round} from "@/utils/stringUtils";
window.Rivers = (function () {
const generate = function (allowErosion = true) {

View file

@ -1,6 +1,7 @@
import {TIME} from "/src/config/logging";
import {findCell} from "/src/utils/graphUtils";
import {last} from "/src/utils/arrayUtils";
import {round} from "@/utils/stringUtils";
window.Routes = (function () {
const getRoads = function () {

View file

@ -2,6 +2,8 @@ import {last} from "/src/utils/arrayUtils";
import {tip} from "/src/scripts/tooltips";
import {wiki} from "@/utils/linkUtils";
import {rn, minmax} from "/src/utils/numberUtils";
import {rand, P, Pint} from "@/utils/probabilityUtils";
import {capitalize} from "@/utils/stringUtils";
export class Battle {
constructor(attacker, defender) {

View file

@ -2,6 +2,8 @@ import {findCell} from "/src/utils/graphUtils";
import {tip, clearMainTip} from "/src/scripts/tooltips";
import {rn} from "/src/utils/numberUtils";
import {prompt} from "@/scripts/prompt";
import {rand} from "@/utils/probabilityUtils";
import {parseTransform} from "@/utils/stringUtils";
export function editBurg(id) {
if (customization) return;

View file

@ -2,6 +2,7 @@ import {getPackPolygon} from "/src/utils/graphUtils";
import {tip} from "/src/scripts/tooltips";
import {clipPoly} from "@/utils/lineUtils";
import {rn} from "/src/utils/numberUtils";
import {round} from "@/utils/stringUtils";
export function editCoastline(node = d3.event.target) {
if (customization) return;

View file

@ -3,6 +3,7 @@ import {findCell} from "/src/utils/graphUtils";
import {byId} from "/src/utils/shorthands";
import {tip} from "/src/scripts/tooltips";
import {rn, minmax, normalize} from "/src/utils/numberUtils";
import {parseTransform} from "@/utils/stringUtils";
// clear elSelected variable
export function unselect() {

View file

@ -2,6 +2,7 @@ import {clearMainTip} from "/src/scripts/tooltips";
import {tip} from "/src/scripts/tooltips";
import {openURL} from "@/utils/linkUtils";
import {rn} from "/src/utils/numberUtils";
import {parseTransform} from "@/utils/stringUtils";
export function editEmblem(type, id, el) {
if (customization) return;

View file

@ -1,6 +1,8 @@
import {findGridCell, getGridPolygon} from "/src/utils/graphUtils";
import {tip, clearMainTip} from "/src/scripts/tooltips";
import {rn} from "/src/utils/numberUtils";
import {ra} from "@/utils/probabilityUtils";
import {parseTransform} from "@/utils/stringUtils";
export function editIce() {
if (customization) return;

View file

@ -1,5 +1,7 @@
import {findCell} from "/src/utils/graphUtils";
import {tip, showMainTip} from "/src/scripts/tooltips";
import {round, parseTransform} from "@/utils/stringUtils";
import {parseTransform} from "@/utils/stringUtils";
export function editLabel() {
if (customization) return;

View file

@ -1,6 +1,8 @@
import {getPackPolygon} from "/src/utils/graphUtils";
import {tip} from "/src/scripts/tooltips";
import {rn} from "/src/utils/numberUtils";
import {rand} from "@/utils/probabilityUtils";
import {round} from "@/utils/stringUtils";
export function editLake() {
if (customization) return;

View file

@ -9,6 +9,7 @@ import {clipPoly} from "@/utils/lineUtils";
import {rn, minmax, normalize} from "/src/utils/numberUtils";
import {isCtrlClick} from "@/utils/keyboardUtils";
import {prompt} from "@/scripts/prompt";
import {rand, P} from "@/utils/probabilityUtils";
let presets = {};
restoreCustomPresets(); // run on-load

View file

@ -1,6 +1,7 @@
import {tip} from "/src/scripts/tooltips";
import {wiki} from "@/utils/linkUtils";
import {rn} from "/src/utils/numberUtils";
import {capitalize} from "@/utils/stringUtils";
export function overviewMilitary() {
if (customization) return;

View file

@ -4,6 +4,7 @@ import {lock, locked} from "/src/scripts/options/lock";
import {tip, clearMainTip} from "/src/scripts/tooltips";
import {byId, stored} from "/src/utils/shorthands";
import {rn, minmax} from "/src/utils/numberUtils";
import {rand, P, gauss} from "@/utils/probabilityUtils";
$("#optionsContainer").draggable({handle: ".drag-trigger", snap: "svg", snapMode: "both"});
$("#exitCustomization").draggable({handle: "div"});

View file

@ -4,6 +4,8 @@ import {unique} from "/src/utils/arrayUtils";
import {tip, showMainTip, clearMainTip} from "/src/scripts/tooltips";
import {getRandomColor} from "/src/utils/colorUtils";
import {rn} from "/src/utils/numberUtils";
import {rand, P} from "@/utils/probabilityUtils";
import {parseTransform} from "@/utils/stringUtils";
export function editProvinces() {
if (customization) return;

View file

@ -3,6 +3,7 @@ import {findCell} from "/src/utils/graphUtils";
import {last} from "/src/utils/arrayUtils";
import {tip, clearMainTip} from "/src/scripts/tooltips";
import {rn} from "/src/utils/numberUtils";
import {capitalize} from "@/utils/stringUtils";
export function editRegiment(selector) {
if (customization) return;

View file

@ -2,6 +2,7 @@ import {findCell} from "/src/utils/graphUtils";
import {last} from "/src/utils/arrayUtils";
import {tip, clearMainTip} from "/src/scripts/tooltips";
import {rn} from "/src/utils/numberUtils";
import {capitalize} from "@/utils/stringUtils";
export function overviewRegiments(state) {
if (customization) return;

View file

@ -2,6 +2,7 @@ import {findCell, getPackPolygon} from "/src/utils/graphUtils";
import {tip, clearMainTip} from "/src/scripts/tooltips";
import {getSegmentId} from "@/utils/lineUtils";
import {rn} from "/src/utils/numberUtils";
import {rand} from "@/utils/probabilityUtils";
export function editRiver(id) {
if (customization) return;

View file

@ -1,6 +1,8 @@
import {tip, showMainTip, clearMainTip} from "/src/scripts/tooltips";
import {getSegmentId} from "@/utils/lineUtils";
import {rn} from "/src/utils/numberUtils";
import {getNextId} from "@/utils/nodeUtils";
import {round} from "@/utils/stringUtils";
export function editRoute(onClick) {
if (customization) return;

View file

@ -1,5 +1,6 @@
import {tip} from "/src/scripts/tooltips";
import {rn} from "/src/utils/numberUtils";
import {parseTransform} from "@/utils/stringUtils";
// add available filters to lists
{

View file

@ -1,4 +1,5 @@
import {tip} from "/src/scripts/tooltips";
import {isJsonValid} from "@/utils/stringUtils";
const systemPresets = [
"default",
@ -45,7 +46,7 @@ async function getStylePreset(desiredPreset) {
ERROR && console.error(`Custom style ${desiredPreset} in not found in localStorage. Applying default style`);
presetToLoad = "default";
} else {
const isValid = JSON.isValid(storedStyleJSON);
const isValid = isJsonValid(storedStyleJSON);
if (isValid) return [desiredPreset, JSON.parse(storedStyleJSON)];
ERROR &&
@ -330,7 +331,7 @@ function addStylePreset() {
const desiredName = styleSaverName.value;
if (!styleJSON) return tip("Please provide a style JSON", false, "error");
if (!JSON.isValid(styleJSON)) return tip("JSON string is not valid, please check the format", false, "error");
if (!isJsonValid(styleJSON)) return tip("JSON string is not valid, please check the format", false, "error");
if (!desiredName) return tip("Please provide a preset name", false, "error");
if (styleSaverTip.innerHTML === "default")
return tip("You cannot overwrite default preset, please change the name", false, "error");
@ -350,7 +351,7 @@ function addStylePreset() {
const styleName = styleSaverName.value;
if (!styleJSON) return tip("Please provide a style JSON", false, "error");
if (!JSON.isValid(styleJSON)) return tip("JSON string is not valid, please check the format", false, "error");
if (!isJsonValid(styleJSON)) return tip("JSON string is not valid, please check the format", false, "error");
if (!styleName) return tip("Please provide a preset name", false, "error");
downloadFile(styleJSON, styleName + ".json", "application/json");
@ -362,7 +363,7 @@ function addStylePreset() {
function styleUpload(dataLoaded) {
if (!dataLoaded) return tip("Cannot load the file. Please check the data format", false, "error");
const isValid = JSON.isValid(dataLoaded);
const isValid = isJsonValid(dataLoaded);
if (!isValid) return tip("Loaded data is not a valid JSON, please check the format", false, "error");
styleSaverJSON.value = JSON.stringify(JSON.parse(dataLoaded), null, 2);

View file

@ -1,5 +1,6 @@
import {tip} from "/src/scripts/tooltips";
import {rn} from "/src/utils/numberUtils";
import {round} from "@/utils/stringUtils";
export function showBurgTemperatureGraph(id) {
const b = pack.burgs[id];

View file

@ -5,6 +5,8 @@ import {tip, clearMainTip} from "/src/scripts/tooltips";
import {rn} from "/src/utils/numberUtils";
import {isCtrlClick} from "@/utils/keyboardUtils";
import {prompt} from "@/scripts/prompt";
import {getNextId} from "@/utils/nodeUtils";
import {P, generateSeed} from "@/utils/probabilityUtils";
toolsContent.addEventListener("click", function (event) {
if (customization) return tip("Please exit the customization mode first", false, "warning");

View file

@ -1,5 +1,6 @@
import {tip} from "/src/scripts/tooltips";
import {rn} from "/src/utils/numberUtils";
import {round, parseTransform} from "@/utils/stringUtils";
export function editWorld() {
if (customization) return;

View file

@ -3,6 +3,7 @@ import {findAll, findCell, getPackPolygon} from "/src/utils/graphUtils";
import {unique} from "/src/utils/arrayUtils";
import {tip, showMainTip, clearMainTip} from "/src/scripts/tooltips";
import {rn} from "/src/utils/numberUtils";
import {getNextId} from "@/utils/nodeUtils";
export function editZones() {
closeDialogs();

View file

@ -25,6 +25,7 @@ import {parseError} from "@/utils/errorUtils";
import {rn, minmax, normalize} from "./utils/numberUtils";
import {createTypedArray} from "./utils/arrayUtils";
import {clipPoly} from "@/utils/lineUtils";
import {rand, P, gauss, ra, rw, generateSeed} from "@/utils/probabilityUtils";
import {byId} from "./utils/shorthands";
import "./components";

View file

@ -1,4 +1,5 @@
import {rn} from "../utils/numberUtils";
import {parseTransform} from "@/utils/stringUtils";
export function drawLegend(name: string, data: unknown[]) {
legend.selectAll("*").remove(); // fully redraw every time

View file

@ -2,6 +2,7 @@ import {findCell} from "/src/utils/graphUtils";
import {last} from "/src/utils/arrayUtils";
import {getSegmentId} from "@/utils/lineUtils";
import {rn} from "/src/utils/numberUtils";
import {round, parseTransform} from "@/utils/stringUtils";
export class Rulers {
constructor() {

View file

@ -70,7 +70,7 @@ function showNotes(event: Event) {
// show viewbox tooltip if main tooltip is blank
function showMapTooltip(point: number[], event: Event, packCellId: number, gridCellId: number) {
tip(""); // clear tip
const path = event.composedPath ? event.composedPath() : getComposedPath(event.target); // apply polyfill
const path = event.composedPath();
if (!path[path.length - 8]) return;
const group = path[path.length - 7].id;
const subgroup = path[path.length - 8].id;

View file

@ -1,4 +1,4 @@
"use strict";
import {P} from "@/utils/probabilityUtils";
// chars that serve as vowels
const VOWELS = `aeiouyɑ'əøɛœæɶɒɨɪɔɐʊɤɯаоиеёэыуюяàèìòùỳẁȁȅȉȍȕáéíóúýẃőűâêîôûŷŵäëïöüÿẅãẽĩõũỹąęįǫųāēīōūȳăĕĭŏŭǎěǐǒǔȧėȯẏẇạẹịọụỵẉḛḭṵṳ`;

7
src/utils/nodeUtils.ts Normal file
View file

@ -0,0 +1,7 @@
import {byId} from "./shorthands";
// get next unused id
export function getNextId(core: string, index = 1) {
while (byId(core + index)) index++;
return core + index;
}

View file

@ -0,0 +1,84 @@
import {ERROR} from "@/config/logging";
import {minmax, rn} from "./numberUtils";
const d3 = window.d3;
// random number in range
export function rand(min: number, max: number) {
if (min === undefined && max === undefined) return Math.random();
if (max === undefined) {
max = min;
min = 0;
}
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// probability shorthand
export function P(probability: number) {
if (probability >= 1) return true;
if (probability <= 0) return false;
return Math.random() < probability;
}
export function each(n: number) {
return (i: number) => i % n === 0;
}
// random number using normal distribution
export function gauss(expected = 100, deviation = 30, min = 0, max = 300, round = 0) {
const randomValue = d3.randomNormal(expected, deviation);
const clamped = minmax(randomValue(), min, max);
return rn(clamped, round);
}
// probability shorthand for floats
export function Pint(float: number) {
return ~~float + +P(float % 1);
}
// return random value from the array
export function ra<T>(array: T[]) {
return array[Math.floor(Math.random() * array.length)];
}
// return random value from weighted array
export function rw(object: {[key: string]: number}) {
const weightedArray = Object.entries(object)
.map(([choise, weight]) => new Array(weight).fill(choise))
.flat();
return ra(weightedArray);
}
// return a random integer from min to max biased towards one end based on exponent distribution (the bigger ex the higher bias towards min)
export function biased(min: number, max: number, ex: number) {
return Math.round(min + (max - min) * Math.pow(Math.random(), ex));
}
// get number from string in format "1-3" or "2" or "0.5"
export function getNumberInRange(rangeString: string) {
if (typeof rangeString !== "string") {
ERROR && console.error("The value should be a string", rangeString);
return 0;
}
const rangeNumber = Number(rangeString);
if (!isNaN(rangeNumber)) return Pint(rangeNumber);
const negative = rangeString.startsWith("-");
const sign = negative ? -1 : 1;
if (negative) rangeString = rangeString.substring(1);
const [min, max] = rangeString.split("-");
const count = rand(sign * +min, +max);
if (isNaN(count) || count < 0) {
ERROR && console.error("Cannot parse number. Check the format", rangeString);
return 0;
}
return count;
}
export function generateSeed() {
return String(Math.floor(Math.random() * 1e9));
}

View file

@ -1,22 +1,21 @@
import {rn} from "/src/utils/numberUtils";
import {rn} from "@/utils/numberUtils";
// round numbers in string to d decimals
function round(s, d = 1) {
return s.replace(/[\d\.-][\d\.e-]*/g, function (n) {
return rn(n, d);
});
export function round(str: string, d = 1) {
return str.replace(/[\d\.-][\d\.e-]*/g, n => String(rn(+n, d)));
}
// return string with 1st char capitalized
function capitalize(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
export function capitalize(str: string) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
// split string into 2 almost equal parts not breaking words
function splitInTwo(str) {
export function splitInTwo(str: string) {
const half = str.length / 2;
const ar = str.split(" ");
if (ar.length < 2) return ar; // only one word
let first = "",
last = "",
middle = "",
@ -36,10 +35,10 @@ function splitInTwo(str) {
}
// transform string to array [translateX,translateY,rotateDeg,rotateX,rotateY,scale]
function parseTransform(string) {
if (!string) return [0, 0, 0, 0, 0, 1];
export function parseTransform(str: string) {
if (!str) return [0, 0, 0, 0, 0, 1];
const a = string
const a = str
.replace(/[a-z()]/g, "")
.replace(/[ ]/g, ",")
.split(",");
@ -47,7 +46,7 @@ function parseTransform(string) {
}
// check if string is a valid for JSON parse
JSON.isValid = str => {
export const isJsonValid = (str: string) => {
try {
JSON.parse(str);
} catch (e) {

View file

@ -1,30 +0,0 @@
"use strict";
// FMG utils related to nodes
// remove parent element (usually if child is clicked)
function removeParent() {
this.parentNode.parentNode.removeChild(this.parentNode);
}
// polyfill for composedPath
function getComposedPath(node) {
let parent;
if (node.parentNode) parent = node.parentNode;
else if (node.host) parent = node.host;
else if (node.defaultView) parent = node.defaultView;
if (parent !== undefined) return [node].concat(getComposedPath(parent));
return [node];
}
// get next unused id
function getNextId(core, i = 1) {
while (document.getElementById(core + i)) i++;
return core + i;
}
function getAbsolutePath(href) {
if (!href) return "";
const link = document.createElement("a");
link.href = href;
return link.href;
}

View file

@ -1,79 +0,0 @@
import {rn, minmax} from "/src/utils/numberUtils";
// random number in a range
function rand(min, max) {
if (min === undefined && max === undefined) return Math.random();
if (max === undefined) {
max = min;
min = 0;
}
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// probability shorthand
function P(probability) {
if (probability >= 1) return true;
if (probability <= 0) return false;
return Math.random() < probability;
}
function each(n) {
return i => i % n === 0;
}
// random number (normal or gaussian distribution)
function gauss(expected = 100, deviation = 30, min = 0, max = 300, round = 0) {
return rn(minmax(d3.randomNormal(expected, deviation)(), min, max), round);
}
// probability shorthand for floats
function Pint(float) {
return ~~float + +P(float % 1);
}
// return random value from the array
function ra(array) {
return array[Math.floor(Math.random() * array.length)];
}
// return random value from weighted array {"key1":weight1, "key2":weight2}
function rw(object) {
const array = [];
for (const key in object) {
for (let i = 0; i < object[key]; i++) {
array.push(key);
}
}
return array[Math.floor(Math.random() * array.length)];
}
// return a random integer from min to max biased towards one end based on exponent distribution (the bigger ex the higher bias towards min)
function biased(min, max, ex) {
return Math.round(min + (max - min) * Math.pow(Math.random(), ex));
}
// get number from string in format "1-3" or "2" or "0.5"
function getNumberInRange(r) {
if (typeof r !== "string") {
ERROR && console.error("The value should be a string", r);
return 0;
}
if (!isNaN(+r)) return ~~r + +P(r - ~~r);
const sign = r[0] === "-" ? -1 : 1;
if (isNaN(+r[0])) r = r.slice(1);
const range = r.includes("-") ? r.split("-") : null;
if (!range) {
ERROR && console.error("Cannot parse the number. Check the format", r);
return 0;
}
const count = rand(range[0] * sign, +range[1]);
if (isNaN(count) || count < 0) {
ERROR && console.error("Cannot parse number. Check the format", r);
return 0;
}
return count;
}
function generateSeed() {
return String(Math.floor(Math.random() * 1e9));
}