-
Notifications
You must be signed in to change notification settings - Fork 1
/
math.js
138 lines (121 loc) · 3.71 KB
/
math.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
import lcm from 'compute-lcm';
/**
* Returns the least common multiple for two or more numbers.
* Can be specified as separate parameters or an array of numbers.
*
* Full docs:
* - https://github.com/compute-io/lcm
*
* @param {number[]} ...numbers - two or more numbers
* @returns {number} the least common multiple
*/
export const leastCommonMultiple = lcm;
/**
* Returns the greatest common divisor for two numbers.
*
* @param {number} x - the first number
* @param {number} y - the second number
* @returns {number} the greatest common divisor
*/
export const greatestCommonDivisor = (x, y) => {
if (!y) {
return Math.abs(x);
}
return greatestCommonDivisor(y, x % y);
};
/**
* Accepts a numerator and denominator and returns a tuple with a reduced
* numerator/denominator pair.
*
* @param {number} numerator
* @param {number} denominator
* @returns {number[]} a reduced numerator and denominator
*/
const reduceFraction = (numerator, denominator) => {
const gcd = greatestCommonDivisor(numerator, denominator);
return [
numerator / gcd,
denominator / gcd
];
};
/**
* Returns the same value back again.
*
* @param {*} x - the value
* @returns {*} the same value
*/
export const identity = x => x;
/**
* Sums an array of numbers.
*
* @param {number[]} nums - an array of numbers
* @returns {number} the sum of all numbers
*/
export const sum = nums => nums.reduce((total, num) => total + num, 0);
const firstOfSort = (items, sortFn) => items.slice().sort(sortFn)[0];
/**
* Returns the least item in an array. Accepts an optional mapping function
* to transform each item before comparing.
*
* @param {Array} items - an array of values to compare
* @param {function} [xform] - a mapping function
* @returns {*} the least item in the array
*/
export const least = (items, xform = identity) => (
firstOfSort(items, (a, b) => xform(a) - xform(b))
);
/**
* Returns the greatest item in an array. Accepts an optional mapping function
* to transform each item before comparing.
*
* @param {Array} items - an array of values to compare
* @param {function} [xform] - a mapping function
* @returns {*} the greatest item in the array
*/
export const greatest = (items, xform = identity) => (
firstOfSort(items, (a, b) => xform(b) - xform(a))
);
/**
* Checks if a number is between a min (inclusive) and max (non-inclusive).
*
* @param {number} number - the number to check
* @param {number} min - the start of the valid range
* @param {number} min - the end of the valid range (non-inclusive)
* @returns {boolean} whether the number is between the min and max
*/
export const between = (number, min, max) => number >= min && number < max;
/**
* Runs an exclusive-OR (XOR) operation on two values.
*
* @param {*} a - the first value
* @param {*} b - the second value
* @returns {boolean} whether the values pass the XOR
*/
export const xor = (a, b) => (a || b) && !(a && b);
/**
* Takes a line defined by four points and returns an array of X/Y tuples.
* Each pair of coordinates corresponds to a point on the line
* (including both the start and end points).
*
* Note that points are only included if they have whole integer coordinates.
*
* @param {number} x1 - the X of the start point
* @param {number} y1 - the Y of the start point
* @param {number} x2 - the X of the end point
* @param {number} y2 - the Y of the end point
* @returns {Array<Array<number>>} an array of X/Y tuples
*/
export const lineToPoints = (x1, y1, x2, y2) => {
const [ySlope, xSlope] = reduceFraction(y2 - y1, x2 - x1);
const points = [];
let x = x1;
let y = y1;
while (true) {
points.push([x, y]);
if (x === x2 && y === y2) {
return points;
}
x += xSlope;
y += ySlope;
}
};