import { injectable } from "tsyringe"; @injectable() export class MathUtil { /** * Helper to create the sum of all array elements * @param {array} values The array with numbers of which to calculate the sum * @return {number} sum(values) */ public arraySum(values: number[]): number { // sum with initial value being 0 return values.reduce((sum, x) => sum + x, 0); } /** * Helper to create the cumulative sum of all array elements * arrayCumsum([1, 2, 3, 4]) = [1, 3, 6, 10] * @param {array} values The array with numbers of which to calculate the cumulative sum * @return {array} cumsum(values) */ public arrayCumsum(values: number[]): number[] { // curried function for cumulative sum: (cum, x) => cum += x // and 0 being the initial value for the map return values.map((cum => x => cum += x)(0)); } /** * Helper to create the product of each element times factor * @param {array} values The array of numbers which shall be multiplied by the factor * @return {array} array times factor */ public arrayProd(values: number[], factor: number): number[] { return values.map(x => x * factor); } /** * Helper to add a constant to all array elements * @param {array} values The array of numbers to which the summand should be added * @return {array} array plus summand */ public arrayAdd(values: number[], summand: number): number[] { return values.map(x => x + summand); } /** * Map a value from an input range to an output range linearly * * Example: * a_min = 0; a_max=1; * b_min = 1; b_max=3; * MathUtil.mapToRange(0.5, a_min, a_max, b_min, b_max) // returns 2 * * @param {number} x The value from input range to be mapped to output range * @param {number} minIn min of input range * @param {number} maxIn max of input range * @param {number} minOut min of output range * @param {number} maxOut max of outout range * @return {number} the result of the mapping */ public mapToRange(x: number, minIn: number, maxIn: number, minOut: number, maxOut: number): number { const deltaIn = maxIn - minIn; const deltaOut = maxOut - minOut; const xScale = (x - minIn) / deltaIn; return Math.max(minOut, Math.min(maxOut, minOut + xScale * deltaOut)); } /** * Linear interpolation * e.g. used to do a continuous integration for quest rewards which are defined for specific support centers of pmcLevel * * @param {string} xp the point of x at which to interpolate * @param {array} x support points in x (of same length as y) * @param {array} y support points in y (of same length as x) * @return {number} y(xp) */ public interp1(xp: number, x: number[], y: number[]): number { if (xp > x[x.length - 1]) { return y[y.length - 1]; } else if (xp < x[0]) { return y[0]; } else { for (let i = 0; i < x.length - 1; i++) { if (xp >= x[i] && xp <= x[i + 1]) { return y[i] + (xp - x[i]) * (y[i + 1] - y[i]) / (x[i + 1] - x[i]); } } } } }