/** * @description Normalize a value to a 0-1 range based on min and max. * * @example * ``` * // Expect: 0.5 * const example1 = normalize(5, 0, 10) * // Expect: 0 * const example2 = normalize(2, 2, 6) * ``` */ export const normalize = (value: number, min: number, max: number): number => { if (min === max) { throw new Error("Min and max value are the same.") } if (value < min || value > max) { throw new Error(`Value ${value} is not in the range of ${min} to ${max}.`) } return (value - min) / (max - min) } /** * @description Check if a number is even. * * @example * ``` * // Expect: true * const example1 = isEven(10) * // Expect: false * const example2 = isEven(7) * ``` */ export const isEven = (x: number): boolean => x % 2 === 0 /** * @description Check if a number is odd. * * @example * ``` * // Expect: true * const example1 = isOdd(7) * // Expect: false * const example2 = isOdd(10) * ``` */ export const isOdd = (x: number): boolean => x % 2 !== 0 /** * @description Clamp a number to a maximum value. * * @example * ``` * // Expect: 5 * const example1 = maxTo(5, 10) * // Expect: 3 * const example2 = maxTo(5, 3) * ``` */ export const maxTo = (max: number, x: number): number => (x > max ? max : x) /** * @description Clamp a number to a minimum value. * * @example * ``` * // Expect: 5 * const example1 = minTo(5, 3) * // Expect: 8 * const example2 = minTo(5, 8) * ``` */ export const minTo = (min: number, x: number): number => (x < min ? min : x) /** * @description Get the smaller of two numbers. * * @example * ``` * // Expect: 2 * const example1 = minOf(2, 9) * // Expect: -1 * const example2 = minOf(5, -1) * ``` */ export const minOf = (x: number, y: number): number => (x < y ? x : y) /** * @description Get the larger of two numbers. * * @example * ``` * // Expect: 9 * const example1 = maxOf(2, 9) * // Expect: 5 * const example2 = maxOf(5, -1) * ``` */ export const maxOf = (x: number, y: number): number => (x > y ? x : y) /** * @description Clamp a number between two bounds. * * @example * ``` * // Expect: 5 * const example1 = between(0, 10, 5) * // Expect: 0 * const example2 = between(0, 10, -3) * ``` */ export const between = (a: number, b: number, x: number): number => { const min = minOf(a, b) const max = maxOf(a, b) return x < min ? min : x > max ? max : x } /** * @description Get a random integer between min and max, inclusive. * * @example * ``` * // Expect: 4 * const example1 = randomBetween(4, 4) * // Expect: 10 * const example2 = randomBetween(10, 10) * ``` */ export const randomBetween = (min: number, max: number): number => { return Math.floor(Math.random() * (max - min + 1) + min) } /** * @description Get a random integer between two values, regardless of order, inclusive. * * @example * ``` * // Expect: 4 * const example1 = randomIntBetween(4, 4) * // Expect: 10 * const example2 = randomIntBetween(10, 10) * ``` */ export const randomIntBetween = (a: number, b: number): number => { const min = minOf(a, b) const max = maxOf(a, b) return Math.floor(Math.random() * (max - min + 1)) + min } export interface NumberConstraints { min?: number | undefined max?: number | undefined step?: number | undefined } /** * @description Constrain a number by step size and min/max bounds. * * @example * ``` * // Expect: 10 * const example1 = constrainNumber(12, { step: 5, max: 10 }) * // Expect: 3 * const example2 = constrainNumber(2.6, { step: 0.5, min: 3 }) * ``` */ export const constrainNumber = (value: number, constraints: NumberConstraints): number => { let constrainedValue = value if (constraints.step !== undefined) { constrainedValue = Math.round(constrainedValue / constraints.step) * constraints.step } if (constraints.min !== undefined) { constrainedValue = Math.max(constraints.min, constrainedValue) } if (constraints.max !== undefined) { constrainedValue = Math.min(constraints.max, constrainedValue) } return constrainedValue }