/*
* For C# functions that use "params string[] rest" type arguments (where you can either pass in an array,
* or keep passing in additional function arguments that will be placed into an array)
* this function can be called, and given the "arguments" value as the first param, and the number of 'base'
* function arguments as the second param, and it will return the aggregated array
*/
function restArgs(args, numArgs)
{
var ret = [];
if (args.length == numArgs + 1 && Array.isArray(args[numArgs]))
{
ret = args[numArgs];
}
else
{
ret = Array.apply(null, args).slice(numArgs);
}
return ret;
}
Object.defineProperty(Object.prototype, 'addRange', {
enumerable: false,
value: function(more) {
for (var key of Object.keys(more))
{
this[key] = more[key];
}
}
});
Object.defineProperty(Object.prototype, 'containsKey', {
enumerable: false,
value: function(key) {
if (this[key] !== undefined)
{
return true;
}
return false;
}
});
// handy dandy function that SHOULD ALREADY EXIST IN THE ARRAY object, but doesn't because JAVASCRIPT HATES DEVELOPERS
Object.defineProperty(Array.prototype, 'remove', {
enumerable: false,
value: function(elem) {
var index = this.indexOf(elem);
if (index != -1)
{
this.splice(index, 1);
return true;
}
return false;
}
});
Object.defineProperty(Array.prototype, 'contains', {
enumerable: false,
value: function(elem) { return this.indexOf(elem) != -1; }
});
Object.defineProperty(Array.prototype, 'any', {
enumerable: false,
value: function(func) { return this.some(func || function(x) { return x }); }
});
Object.defineProperty(Array.prototype, 'getRandomElement', {
enumerable: false,
value: function() { return this.length == 0 ? null : this[Math.floor(Engine.Utils.randomDouble() * this.length)]; }
});
Object.defineProperty(Array.prototype, 'last', {
enumerable: false,
value: function(func) { return this[this.length - 1]; }
});
Object.defineProperty(Array.prototype, 'firstOrDefault', {
enumerable: false,
value: function(filter /*optional*/) {
if (filter !== undefined && typeof filter === "function")
{
for (var i = 0; i < this.length; i++)
{
if (filter(this[i])) return this[i];
}
return null;
}
return this.length == 0 ? null : this[0];
}
});
Object.defineProperty(Array.prototype, 'lastOrDefault', {
enumerable: false,
value: function(filter /*optional*/) {
if (filter !== undefined && typeof filter === "function")
{
for (var i = this.length - 1; i >= 0; i--)
{
if (filter(this[i])) return this[i];
}
return null;
}
return this.length == 0 ? null : this[this.length - 1];
}
});
Object.defineProperty(Array.prototype, 'flatten', {
enumerable: false,
value: function() {
var ret = [];
for (var i of this)
{
if (Array.isArray(i))
{
for (var j of i)
{
ret.push(j);
}
}
else
{
ret.push(i);
}
}
return ret;
}
});
Object.defineProperty(Array.prototype, 'average', {
enumerable: false,
value: function(func) {
if (this.length == 0) return undefined;
var sum = 0;
for (var i in this)
{
sum += (func === undefined) ? this[i] : func(this[i]);
}
return sum / this.length;
}
});
Object.defineProperty(Array.prototype, 'all', {
enumerable: false,
value: function(func) {
for (var i = 0; i < this.length; i++)
{
if (!func(this[i])) return false;
}
return true;
}
});
Object.defineProperty(Array.prototype, 'none', {
enumerable: false,
value: function(func) {
for (var i = 0; i < this.length; i++)
{
if (func(this[i])) return false;
}
return true;
}
});
Object.defineProperty(Array.prototype, 'max', {
enumerable: false,
value: function(func) {
var max = Number.MIN_VALUE;
if (this.length == 0) return 0;
if (func === undefined) func = (v) => { return v;}
for (var i = 0; i < this.length; i++)
{
var val = func(this[i]);
if (val > max) max = val;
}
return max;
}
});
Object.defineProperty(Array.prototype, 'maxItem', {
enumerable: false,
value: function(func) {
var max = Number.MIN_VALUE;
var maxIndex = 0;
if (this.length == 0) return null;
if (func === undefined) func = (v) => { return v;}
for (var i = 0; i < this.length; i++)
{
var val = func(this[i]);
if (val > max)
{
maxIndex = i;
max = val;
}
}
return this[maxIndex];
}
});
Object.defineProperty(Array.prototype, 'min', {
enumerable: false,
value: function(func)
{
var min = Number.MAX_VALUE;
if (this.length == 0) return 0;
if (func === undefined) func = (v) => { return v;}
for (var i = 0; i < this.length; i++)
{
var val = func(this[i]);
if (val < min) min = val;
}
return min;
}
});
Object.defineProperty(Array.prototype, 'sum', {
enumerable: false,
value: function(func) {
var sum = 0;
for (var i = 0; i < this.length; i++)
{
sum += func(this[i]);
}
return sum;
}
});
Object.defineProperty(Array.prototype, 'addRange', {
enumerable: false,
value: function(more) {
if (Array.isArray(more))
{
for (var i = 0; i < more.length; i++)
{
this.push(more[i]);
}
}
else if (more instanceof Set)
{
this.addRange(more.values);
}
}
});
Object.defineProperty(Array.prototype, 'removeRange', {
enumerable: false,
value: function(remove) {
if (Array.isArray(remove))
{
for (var i = 0; i < remove.length; i++)
{
var index = this.indexOf(remove[i]);
if (index != -1)
{
this.splice(index, 1);
}
}
}
else if (remove instanceof Set)
{
this.removeRange(remove.values);
}
}
});
String.prototype.replaceAll = function(search, replacement) {
var target = this;
return target.split(search).join(replacement);
};
String.prototype.effectKey = function() {
var target = this;
return target.split(",")[0];
};
String.prototype.toCamelCase = function(firstUpper) {
var target = this;
if (firstUpper === undefined) firstUpper = true;
var result = target.replace(/(?:^\w|[A-Z]|\b\w)/g, function(letter, index) { return index == 0 && !firstUpper ? letter.toLowerCase() : letter.toUpperCase(); }).replace(/\s+/g, '');
return result;
};
String.prototype.toUnderlineCase = function(search, replacement) {
var target = this;
var toUnderlineCaseReg = /[^A-Z0-9][A-Z0-9]/g;
return target.replace(toUnderlineCaseReg, match => [match.slice(0, 1), "_", match.slice(1)].join('')).toLowerCase();
};
Object.defineProperty(Array.prototype, 'distinct', {
enumerable: false,
value: function()
{
return this.filter((value, index, self) => self.indexOf(value) === index);
}
});
Object.defineProperty(Array.prototype, 'sortNum', {
enumerable: false,
value: function()
{
return this.sort((a, b) => a - b);
}
});
Number.isNumeric = function(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
Math.clamp = function(value, min, max) {
return Math.min(Math.max(value, min), max);
};
function isNumeric(n) {
return !isNaN(parseFloat(n)) && isFinite(n);
}
var CircularQueueStatics = {};
CircularQueueStatics.SizeMode = {
Add:0,
Mult:1
}
class CircularQueue
{
constructor(startSize, sizeMode, increase)
{
if (startSize === undefined) startSize = 0;
if (sizeMode === undefined)
{
sizeMode = CircularQueueStatics.SizeMode.Mult;
increase = 2;
}
if (increase === undefined)
{
increase = 2;
if (sizeMode == CircularQueueStatics.SizeMode.Add) increase = 50;
}
startSize = Math.max(0, startSize);
this.startSize = this.startSize;
this.backing = new Array(startSize);
this.sizeMode = sizeMode;
this.increase = increase;
this.start = 0;
this.end = 0;
}
get length() { return (this.end + this.backing.length - this.start) % this.backing.length; }
enqueue(v)
{
if (this.length == this.backing.length)
{
var newSize = this.backing.length + 1;
if (this.sizeMode == CircularQueueStatics.SizeMode.Add)
{
newSize = Math.max(newSize, this.backing.length + this.increase);
}
if (this.sizeMode == CircularQueueStatics.SizeMode.Mult)
{
newSize = Math.max(newSize, Math.ceil(this.backing.length * this.increase));
}
var sizeIncrease = newSize - this.backing.length;
var newBacking = new Array(newSize);
if (this.end >= this.start)
{
for (var i = this.start; i < this.end; i++)
{
newBacking[i] = this.backing[i];
}
}
else
{
for (var i = this.start; i < this.backing.length; i++)
{
newBacking[i + sizeIncrease] = this.backing[i];
}
for (var i = 0; i < this.end; i++)
{
newBacking[i] = this.backing[i];
}
}
this.backing = newBacking;
}
this.backing[this.end] = v;
this.end = (this.end + 1) % this.backing.length;
}
dequeue()
{
if (this.length == 0) return undefined;
var ret = this.backing[this.start];
this.start = (this.start + 1) % this.backing.length;
return ret;
}
pop()
{
if (this.length == 0) return undefined;
var ret = this.backing[this.end];
this.end = (this.end - 1 + this.backing.length) % this.backing.length;
return ret;
}
clear(resetBackingSize)
{
if (resetBackingSize === undefined) resetBackingSize = false;
if (typeof resetBackingSize == "boolean")
{
if (resetBackingSize)
{
this.backing = new Array(this.startSize);
}
}
if (typeof resetBackingSize == "number")
{
this.startSize = Math.max(0, resetBackingSize);
this.backing = new Array(this.startSize);
}
this.start = 0;
this.end = 0;
}
get(index)
{
if (index < 0) return undefined;
if (index >= this.length) return undefined;
index = (this.start + index) % this.backing.length;
return this.backing[index];
}
}