Skip to content

Instantly share code, notes, and snippets.

@peisenmann
Created May 12, 2016 02:54
Show Gist options
  • Select an option

  • Save peisenmann/a578d79957afec0ee110c2dd36e87b9f to your computer and use it in GitHub Desktop.

Select an option

Save peisenmann/a578d79957afec0ee110c2dd36e87b9f to your computer and use it in GitHub Desktop.

Revisions

  1. peisenmann created this gist May 12, 2016.
    8 changes: 8 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,8 @@
    # Pascal's Triangle
    A blind implementation of Pascal's Triangle without any algorithms or optimization research. Uses ES2015 (ES6) level Javascript.

    ## Execution
    Executable in browser or via Node 6+ repl. To run in browser, paste all the code from both `.js` files
    into the console and remove the `export` keyword

    Also executable via GistRun at https://gist.run/?id=bed8e0a105f795f99820ba139f034aaa&sha=2ffda6f14e917df89b8dc0b5c4614e7fc4f8c165
    54 changes: 54 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,54 @@
    <!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>
    28 changes: 28 additions & 0 deletions pascal.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,28 @@
    "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;
    }
    77 changes: 77 additions & 0 deletions pascal.test.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,77 @@
    "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;
    }