Skip to content

Instantly share code, notes, and snippets.

@peisenmann
Created May 12, 2016 02:54
Show Gist options
  • Save peisenmann/a578d79957afec0ee110c2dd36e87b9f to your computer and use it in GitHub Desktop.
Save peisenmann/a578d79957afec0ee110c2dd36e87b9f to your computer and use it in GitHub Desktop.
Pascal's Triangle implementation in ES6
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Pascal's Triangle</title>
<style type="text/css">
.triangle {float: left}
.triangleRow {text-align: center;}
.triangleItem {display: inline-block; width: 2em; text-align: center;}
.clearfix {clear: both;}
</style>
</head>
<body>
<h1>Generated on the left, Hard Coded on the right</h1>
<script src="pascal.js"></script>
<script src="pascal.test.js"></script>
<script>
/* Super hacky testing for visibility and entertainment */
for (var i = 0; i < knownTriangle.length; i++) {
var newPT = pascalsTriangle(i),
knownPT = knownTriangle.slice(0,i+1);
visualizeTriangles(newPT, knownPT);
let hr = document.createElement('hr');
hr.className = 'clearfix';
document.body.appendChild(hr);
}
function visualizeTriangles(...triangles) {
const dce = document.createElement.bind(document);
const dctn = document.createTextNode.bind(document);
let html = triangles.map(triangle => {
let div = dce('div');
div.className = 'triangle';
triangle.forEach(row => {
let rowDiv = dce('div');
rowDiv.className = 'triangleRow';
row.forEach(item => {
var span = dce('span');
span.className = 'triangleItem';
span.appendChild(dctn(item));
rowDiv.appendChild(span);
});
div.appendChild(rowDiv);
});
return div;
});
html.forEach(document.body.appendChild.bind(document.body));
}
</script>
</body>
</html>
"use strict";
/**
* Produces Pascal's triangle up to the given row number
* Example:
pascalsTriangle(5)
[[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1],
[1,5,10,10,5,1]]
* @param {Number} row The highest row returned in the resulting triangle
* @returns {Array<Array<Number>>}} The resulting Pascal's triangle
*/
function pascalsTriangle(row) {
// Guard against bad input
if (!Number.isInteger(row) || row < 0) {
throw new TypeError('row must be a positive integer, but was ' + row);
}
// Base case
let triangle = [[1]];
for (let r = 1; r < row + 1; r++) {
triangle.push(triangle[r-1].concat(0).map((term, i, arr) => term + (arr[i-1] || 0)));
}
return triangle;
}
"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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment