|
"use strict"; |
|
const knownTriangle = [ |
|
[1], |
|
[1,1], |
|
[1,2,1], |
|
[1,3,3,1], |
|
[1,4,6,4,1], |
|
[1,5,10,10,5,1], |
|
[1,6,15,20,15,6,1], |
|
[1,7,21,35,35,21,7,1], |
|
[1,8,28,56,70,56,28,8,1], |
|
[1,9,36,84,126,126,84,36,9,1] |
|
]; |
|
|
|
/** |
|
* |
|
* @param {function} pt The given pascalTriangle function to test |
|
* @returns {boolean | Array<String>} true if the pt function produces valid outputs, an Array<String> errors if not |
|
*/ |
|
function testPascalsTriangle(pt) { |
|
let errors = []; |
|
// Iterate over the sizes of the known triangle and ensure that pt(i) equals the known triangle |
|
for (let i = 0; i < knownTriangle.length; i++) { |
|
let newPT = pt(i), |
|
knownPT = knownTriangle.slice(0,i+1); |
|
if (!equalTriangles(newPT, knownPT)) { |
|
errors.push('Error at pt(' + i + '). Expected\n' + knownPT + '\nbut got\n' + newPT); |
|
} |
|
} |
|
return errors.length ? errors : true; |
|
} |
|
|
|
/** |
|
* Compare if all of the given triangles have the same value in the same position |
|
* @param {...Array} triangles The triangles to compare |
|
* @returns {boolean} true if all triangles are equal, false otherwise |
|
*/ |
|
function equalTriangles(...triangles) { |
|
return strictEquals(...[true].concat(...compareTriangles(...triangles))); |
|
} |
|
|
|
/** |
|
* Produces a position for position mapping of all triangles where true indicates a same value across all triangles |
|
* and false indicates a mismatch or missing value in one or more triangles |
|
* @param {...Array<Array<Number>>} triangles Arbitrary number of 2D arrays that represents a pascal's triangle |
|
* @return {Array<Array<Number>>} a superpositional 2D array representing the matching parts of the given triangles |
|
*/ |
|
function compareTriangles(...triangles) { |
|
// Since we know the exact structure of a triangle is an array of arrays, we can hard code to that level of depth |
|
return coiterate(coiterate.bind(null, strictEquals), ...triangles); |
|
} |
|
|
|
/** |
|
* Iterate across the given arrays and invoke pred(arr1[0], arr2[0], etc) for each index of the arrays up to the length |
|
* of the longest given array |
|
* @param pred The predicate to apply |
|
* @param {...Array} arrays The arrays to coiterate over |
|
* @returns {Array} The result of the predicate applied positionally to each array |
|
*/ |
|
function coiterate(pred, ...arrays) { |
|
let maxLength = arrays.reduce((max, arr) => arr && arr.length > max ? arr.length : max, 0); |
|
return Array.from(Array(maxLength).keys()).map(i => pred(...arrays.map(arr => arr && arr[i]))); |
|
} |
|
|
|
/** |
|
* Given many items as input, return true if all items are strictly equal |
|
* @param {...*} items The items to compare |
|
* @returns {boolean} true if all items are the same, false otherwise |
|
*/ |
|
function strictEquals(...items) { |
|
for (let i = 1; i < items.length; i++) { |
|
if (items[i] !== items[i-1]) { |
|
return false; |
|
} |
|
} |
|
return true; |
|
} |