diff --git a/R/.Rproj.user/CBF2E10B/sources/prop/INDEX b/R/.Rproj.user/CBF2E10B/sources/prop/INDEX
index 1f13eb1..62cc263 100644
--- a/R/.Rproj.user/CBF2E10B/sources/prop/INDEX
+++ b/R/.Rproj.user/CBF2E10B/sources/prop/INDEX
@@ -2,3 +2,4 @@
~%2FDevelopment%2F2020-code-advent%2FR%2F01.py="E3582989"
~%2FDevelopment%2F2020-code-advent%2FREADME.md="87542FC2"
~%2FDevelopment%2F2020-code-advent%2Finput%2F01-01.txt="22EEE1B0"
+~%2FDevelopment%2F2020-code-advent%2Fjs%2F01.js="BCBA9F87"
diff --git a/R/.Rproj.user/shared/notebooks/paths b/R/.Rproj.user/shared/notebooks/paths
index 2a9472a..e457a99 100644
--- a/R/.Rproj.user/shared/notebooks/paths
+++ b/R/.Rproj.user/shared/notebooks/paths
@@ -2,3 +2,4 @@
/Users/hrbrmstr/Development/2020-code-advent/R/01.py="1AD9A8A4"
/Users/hrbrmstr/Development/2020-code-advent/README.md="74DC8DCF"
/Users/hrbrmstr/Development/2020-code-advent/input/01-01.txt="53BE9636"
+/Users/hrbrmstr/Development/2020-code-advent/js/01.js="77D3BDB6"
diff --git a/README.md b/README.md
index 6af519f..facb2d2 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,3 @@
# 2020 Advent of Code
-Solutions in R, Swift, Python (in the `R` dir since I'm using RStudio's Python REPL) and mebbe others
+Solutions in R, Swift, javascript, Python (in the `R` dir since I'm using RStudio's Python REPL) and mebbe others
diff --git a/js/01.js b/js/01.js
new file mode 100644
index 0000000..11d7378
--- /dev/null
+++ b/js/01.js
@@ -0,0 +1,28 @@
+// See R or Python code for the problems
+
+// 01-01
+
+var fs = require("fs")
+var combn = require('generatorics') // npm install generatorics
+
+input = fs.readFileSync("../input/01-01.txt", "utf-8")
+ .split("\n")
+ .map(Number)
+
+for (var pair of combn.combination(input, 2)) {
+ res = pair.reduce((a, b) => a+b)
+ if (res == 2020) {
+ console.log(pair.reduce((a, b) => a*b))
+ break
+ }
+}
+
+// 01-02
+
+for (var pair of combn.combination(input, 3)) {
+ res = pair.reduce((a, b) => a+b)
+ if (res == 2020) {
+ console.log(pair.reduce((a, b) => a*b))
+ break
+ }
+}
diff --git a/js/node_modules/.package-lock.json b/js/node_modules/.package-lock.json
new file mode 100644
index 0000000..43664bb
--- /dev/null
+++ b/js/node_modules/.package-lock.json
@@ -0,0 +1,15 @@
+{
+ "name": "js",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "node_modules/generatorics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/generatorics/-/generatorics-1.1.0.tgz",
+ "integrity": "sha1-aVBgu42IuQmzAXGlyz1CR2hmETg=",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ }
+ }
+}
diff --git a/js/node_modules/generatorics/.eslintrc.json b/js/node_modules/generatorics/.eslintrc.json
new file mode 100644
index 0000000..2a270bf
--- /dev/null
+++ b/js/node_modules/generatorics/.eslintrc.json
@@ -0,0 +1,26 @@
+{
+ "env": {
+ "browser": true,
+ "es6": true,
+ "node": true
+ },
+ "extends": "eslint:recommended",
+ "rules": {
+ "indent": [
+ "error",
+ 2
+ ],
+ "linebreak-style": [
+ "error",
+ "unix"
+ ],
+ "quotes": [
+ "error",
+ "single"
+ ],
+ "semi": [
+ "error",
+ "never"
+ ]
+ }
+}
diff --git a/js/node_modules/generatorics/README.md b/js/node_modules/generatorics/README.md
new file mode 100644
index 0000000..5b7c6ad
--- /dev/null
+++ b/js/node_modules/generatorics/README.md
@@ -0,0 +1,388 @@
+# Generatorics
+
+### An efficient combinatorics library for JavaScript utilizing ES2015 generators. Generate combinations, permutations, and power sets of arrays or strings.
+
+- Node
+```
+npm install generatorics
+```
+```javascript
+var G = require('generatorics');
+```
+
+- Browser
+```
+bower install generatorics
+```
+```html
+
+```
+
+**Note:** This module is not transpiled for compatibility, as it degrades the performance. Check your browser/node version.
+
+## Usage
+
+### power set
+```javascript
+for (var subset of G.powerSet(['a', 'b', 'c'])) {
+ console.log(subset);
+}
+// [ ]
+// [ 'a' ]
+// [ 'a', 'b' ]
+// [ 'a', 'b', 'c' ]
+// [ 'a', 'c' ]
+// [ 'b' ]
+// [ 'b', 'c' ]
+// [ 'c' ]
+```
+
+### permutation
+```javascript
+for (var perm of G.permutation(['a', 'b', 'c'], 2)) {
+ console.log(perm);
+}
+// [ 'a', 'b' ]
+// [ 'a', 'c' ]
+// [ 'b', 'a' ]
+// [ 'b', 'c' ]
+// [ 'c', 'a' ]
+// [ 'c', 'b' ]
+
+for (var perm of G.permutation(['a', 'b', 'c'])) { // assumes full length of array
+ console.log(perm);
+}
+// [ 'a', 'b', 'c' ]
+// [ 'a', 'c', 'b' ]
+// [ 'b', 'a', 'c' ]
+// [ 'b', 'c', 'a' ]
+// [ 'c', 'b', 'a' ]
+// [ 'c', 'a', 'b' ]
+```
+
+### combination
+```javascript
+for (var comb of G.combination(['a', 'b', 'c'], 2)) {
+ console.log(comb);
+}
+// [ 'a', 'b' ]
+// [ 'a', 'c' ]
+// [ 'b', 'c' ]
+```
+
+For efficiency, each array being yielded is the same one being mutated on each iteration. **DO NOT** mutate the array.
+```javascript
+var combs = [];
+for (var comb of G.combination(['a', 'b', 'c'], 2)) {
+ combs.push(comb);
+}
+console.log(combs);
+// [ [ 'b', 'c' ], [ 'b', 'c' ], [ 'b', 'c' ] ]
+```
+You can clone if necessary, or use the [clone submodule](#clone-submodule)
+
+### permutation of combination
+```javascript
+for (var perm of G.permutationCombination(['a', 'b', 'c'])) {
+ console.log(perm);
+}
+// [ ]
+// [ 'a' ]
+// [ 'a', 'b' ]
+// [ 'a', 'b', 'c' ]
+// [ 'a', 'c' ]
+// [ 'a', 'c', 'b' ]
+// [ 'b' ]
+// [ 'b', 'a' ]
+// [ 'b', 'a', 'c' ]
+// [ 'b', 'c' ]
+// [ 'b', 'c', 'a' ]
+// [ 'c' ]
+// [ 'c', 'a' ]
+// [ 'c', 'a', 'b' ]
+// [ 'c', 'b' ]
+// [ 'c', 'b', 'a' ]
+```
+
+### cartesian product
+```javascript
+for (var prod of G.cartesian([0, 1, 2], [0, 10, 20], [0, 100, 200])) {
+ console.log(prod);
+}
+// [ 0, 0, 0 ], [ 0, 0, 100 ], [ 0, 0, 200 ]
+// [ 0, 10, 0 ], [ 0, 10, 100 ], [ 0, 10, 200 ]
+// [ 0, 20, 0 ], [ 0, 20, 100 ], [ 0, 20, 200 ]
+// [ 1, 0, 0 ], [ 1, 0, 100 ], [ 1, 0, 200 ]
+// [ 1, 10, 0 ], [ 1, 10, 100 ], [ 1, 10, 200 ]
+// [ 1, 20, 0 ], [ 1, 20, 100 ], [ 1, 20, 200 ]
+// [ 2, 0, 0 ], [ 2, 0, 100 ], [ 2, 0, 200 ]
+// [ 2, 10, 0 ], [ 2, 10, 100 ], [ 2, 10, 200 ]
+// [ 2, 20, 0 ], [ 2, 20, 100 ], [ 2, 20, 200 ]
+```
+
+### base N
+```javascript
+for (var num of G.baseN(['a', 'b', 'c'])) {
+ console.log(num);
+}
+// [ 'a', 'a', 'a' ], [ 'a', 'a', 'b' ], [ 'a', 'a', 'c' ]
+// [ 'a', 'b', 'a' ], [ 'a', 'b', 'b' ], [ 'a', 'b', 'c' ]
+// [ 'a', 'c', 'a' ], [ 'a', 'c', 'b' ], [ 'a', 'c', 'c' ]
+// [ 'b', 'a', 'a' ], [ 'b', 'a', 'b' ], [ 'b', 'a', 'c' ]
+// [ 'b', 'b', 'a' ], [ 'b', 'b', 'b' ], [ 'b', 'b', 'c' ]
+// [ 'b', 'c', 'a' ], [ 'b', 'c', 'b' ], [ 'b', 'c', 'c' ]
+// [ 'c', 'a', 'a' ], [ 'c', 'a', 'b' ], [ 'c', 'a', 'c' ]
+// [ 'c', 'b', 'a' ], [ 'c', 'b', 'b' ], [ 'c', 'b', 'c' ]
+// [ 'c', 'c', 'a' ], [ 'c', 'c', 'b' ], [ 'c', 'c', 'c' ]
+```
+
+## Clone Submodule
+Each array yielded from the generator is actually the same array in memory, just mutated to have different elements. This is to avoid the unnecessary creation of a bunch of arrays, which consume memory. As a result, you get a strange result when trying to generate an array.
+```javascript
+var combs = G.combination(['a', 'b', 'c'], 2);
+console.log([...combs]);
+// [ [ 'b', 'c' ], [ 'b', 'c' ], [ 'b', 'c' ] ]
+```
+Instead, you can use the clone submodule.
+```javascript
+var combs = G.clone.combination(['a', 'b', 'c'], 2);
+console.log([...combs]);
+// [ [ 'a', 'b' ], [ 'a', 'c' ], [ 'b', 'c' ] ]
+```
+
+### G.clone
+This submodule produces generators that yield a different array on each iteration in case you need to mutate it. The [combination](#module_G.combination), [permutation](#module_G.permutation), [powerSet](#module_G.powerSet), [permutationCombination](#module_G.permutationCombination), [baseN](#module_G.baseN), [baseNAll](#module_G.baseNAll), and [cartesian](#module_G.cartesian) methods are provided on this submodule.
+
+## Cool things to do with ES2015 generators
+```javascript
+var combs = G.clone.combination([1, 2, 3], 2);
+
+// "for-of" loop
+for (let comb of combs) {
+ console.log(comb);
+}
+
+// generate arrays
+Array.from(combs);
+[...combs];
+
+// generate sets
+new Set(combs);
+
+// spreading in function calls
+console.log(...combs);
+```
+
+#### Writing a code generator? Need to produce an infinite stream of minified variable names?
+
+No problem! Just pass in a collection of all your valid characters and start generating.
+
+```javascript
+var mininym = G.baseNAll('abcdefghijklmnopqrstuvwxyz$#')
+var name = mininym.next().value.join('')
+global[name] = 'some value'
+```
+
+#### Card games anyone?
+```javascript
+var cards = [...G.clone.cartesian('♠♥♣♦', 'A23456789JQK')];
+console.log(G.shuffle(cards));
+// [ [ '♦', '6' ], [ '♠', '6' ], [ '♣', '7' ], [ '♥', 'K' ],
+// [ '♣', 'J' ], [ '♥', '4' ], [ '♦', '2' ], [ '♥', '9' ],
+// [ '♦', 'Q' ], [ '♠', 'Q' ], [ '♠', '4' ], [ '♠', 'K' ],
+// [ '♥', '3' ], [ '♥', '7' ], [ '♠', '5' ], [ '♦', '7' ],
+// [ '♥', '5' ], [ '♣', 'Q' ], [ '♣', '9' ], [ '♠', 'A' ],
+// [ '♣', '4' ], [ '♣', '3' ], [ '♥', 'A' ], [ '♥', '8' ],
+// [ '♣', '8' ], [ '♦', '8' ], [ '♠', '8' ], [ '♣', '5' ],
+// [ '♥', '2' ], [ '♥', 'Q' ], [ '♦', 'A' ], [ '♥', '6' ],
+// [ '♠', '2' ], [ '♣', '6' ], [ '♠', '3' ], [ '♦', 'K' ],
+// [ '♦', 'J' ], [ '♠', '7' ], [ '♥', 'J' ], [ '♦', '5' ],
+// [ '♦', '9' ], [ '♦', '3' ], [ '♠', '9' ], [ '♣', '2' ],
+// [ '♣', 'A' ], [ '♣', 'K' ], [ '♦', '4' ], [ '♠', 'J' ] ]
+```
+
+## Documentation
+
+
+## G
+
+* [G](#module_G)
+ * [.factorial(n)](#module_G.factorial) ⇒ Number
+ * [.factoradic(n)](#module_G.factoradic) ⇒ Array
+ * [.P(n, k)](#module_G.P) ⇒ Number
+ * [.C(n, k)](#module_G.C) ⇒ Number
+ * [.choices(n, k, [options])](#module_G.choices) ⇒ Number
+ * [.combination(arr, [size])](#module_G.combination) ⇒ Generator
+ * [.permutation(arr, [size])](#module_G.permutation) ⇒ Generator
+ * [.powerSet(arr)](#module_G.powerSet) ⇒ Generator
+ * [.permutationCombination(arr)](#module_G.permutationCombination) ⇒ Generator
+ * [.baseN(arr, [size])](#module_G.baseN) ⇒ Generator
+ * [.baseNAll(arr)](#module_G.baseNAll) ⇒ Generator
+ * [.cartesian(...sets)](#module_G.cartesian) ⇒ Generator
+ * [.shuffle(arr)](#module_G.shuffle) ⇒ Array
+
+
+
+### G.factorial(n) ⇒ Number
+Calculates a factorial
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Number
- n!
+
+| Param | Type | Description |
+| --- | --- | --- |
+| n | Number
| The number to operate the factorial on. |
+
+
+
+### G.factoradic(n) ⇒ Array
+Converts a number to the factorial number system. Digits are in least significant order.
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Array
- digits of n in factoradic in least significant order
+
+| Param | Type | Description |
+| --- | --- | --- |
+| n | Number
| Integer in base 10 |
+
+
+
+### G.P(n, k) ⇒ Number
+Calculates the number of possible permutations of "k" elements in a set of size "n".
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Number
- n P k
+
+| Param | Type | Description |
+| --- | --- | --- |
+| n | Number
| Number of elements in the set. |
+| k | Number
| Number of elements to choose from the set. |
+
+
+
+### G.C(n, k) ⇒ Number
+Calculates the number of possible combinations of "k" elements in a set of size "n".
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Number
- n C k
+
+| Param | Type | Description |
+| --- | --- | --- |
+| n | Number
| Number of elements in the set. |
+| k | Number
| Number of elements to choose from the set. |
+
+
+
+### G.choices(n, k, [options]) ⇒ Number
+Higher level method for counting number of possible combinations of "k" elements from a set of size "n".
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Number
- Number of possible combinations.
+
+| Param | Type | Description |
+| --- | --- | --- |
+| n | Number
| Number of elements in the set. |
+| k | Number
| Number of elements to choose from the set. |
+| [options] | Object
| |
+| options.replace | Boolean
| Is replacement allowed after each choice? |
+| options.ordered | Boolean
| Does the order of the choices matter? |
+
+
+
+### G.combination(arr, [size]) ⇒ Generator
+Generates all combinations of a set.
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Generator
- yields each combination as an array
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| arr | Array
| String
| | The set of elements. |
+| [size] | Number
| arr.length
| Number of elements to choose from the set. |
+
+
+
+### G.permutation(arr, [size]) ⇒ Generator
+Generates all permutations of a set.
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Generator
- yields each permutation as an array
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| arr | Array
| String
| | The set of elements. |
+| [size] | Number
| arr.length
| Number of elements to choose from the set. |
+
+
+
+### G.powerSet(arr) ⇒ Generator
+Generates all possible subsets of a set (a.k.a. power set).
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Generator
- yields each subset as an array
+
+| Param | Type | Description |
+| --- | --- | --- |
+| arr | Array
| String
| The set of elements. |
+
+
+
+### G.permutationCombination(arr) ⇒ Generator
+Generates the permutation of the combinations of a set.
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Generator
- yields each permutation as an array
+
+| Param | Type | Description |
+| --- | --- | --- |
+| arr | Array
| String
| The set of elements. |
+
+
+
+### G.baseN(arr, [size]) ⇒ Generator
+Generates all possible "numbers" from the digits of a set.
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Generator
- yields all digits as an array
+
+| Param | Type | Default | Description |
+| --- | --- | --- | --- |
+| arr | Array
| String
| | The set of digits. |
+| [size] | Number
| arr.length
| How many digits will be in the numbers. |
+
+
+
+### G.baseNAll(arr) ⇒ Generator
+Infinite generator for all possible "numbers" from a set of digits.
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Generator
- yields all digits as an array
+
+| Param | Type | Description |
+| --- | --- | --- |
+| arr | Array
| String
| The set of digits |
+
+
+
+### G.cartesian(...sets) ⇒ Generator
+Generates the cartesian product of the sets.
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Generator
- yields each product as an array
+
+| Param | Type | Description |
+| --- | --- | --- |
+| ...sets | Array
| String
| variable number of sets of n elements. |
+
+
+
+### G.shuffle(arr) ⇒ Array
+Shuffles an array in place using the Fisher–Yates shuffle.
+
+**Kind**: static method of [G](#module_G)
+**Returns**: Array
- a random, unbiased perutation of arr
+
+| Param | Type | Description |
+| --- | --- | --- |
+| arr | Array
| A set of elements. |
+
diff --git a/js/node_modules/generatorics/bower.json b/js/node_modules/generatorics/bower.json
new file mode 100644
index 0000000..9a25ae9
--- /dev/null
+++ b/js/node_modules/generatorics/bower.json
@@ -0,0 +1,32 @@
+{
+ "name": "generatorics",
+ "version": "1.0.5",
+ "description": "Combinatorics library for JavaScript using ES2015 generator functions. Generate power set, combination, and permutation.",
+ "main": "generatorics.js",
+ "authors": [
+ "Andrew Carlson "
+ ],
+ "license": "MIT",
+ "keywords": [
+ "combinatorics",
+ "combination",
+ "permutation",
+ "powerset",
+ "factoradic",
+ "shuffle"
+ ],
+ "homepage": "https://github.com/acarl005/generatorics",
+ "moduleType": [
+ "amd",
+ "es6",
+ "globals",
+ "node"
+ ],
+ "ignore": [
+ "**/.*",
+ "node_modules",
+ "bower_components",
+ "test",
+ "tests"
+ ]
+}
diff --git a/js/node_modules/generatorics/generatorics.js b/js/node_modules/generatorics/generatorics.js
new file mode 100644
index 0000000..94b8aea
--- /dev/null
+++ b/js/node_modules/generatorics/generatorics.js
@@ -0,0 +1,328 @@
+/*
+ * Licensed under the MIT license.
+ * http://www.opensource.org/licenses/mit-license.php
+ *
+ * References:
+ * http://www.ruby-doc.org/core-2.0/Array.html#method-i-combination
+ * http://www.ruby-doc.org/core-2.0/Array.html#method-i-permutation
+ */
+
+(function(root, factory) {
+ if (typeof define === 'function' && define.amd) {
+ define([], factory)
+ } else if (typeof exports === 'object') {
+ module.exports = factory()
+ } else {
+ root.G = factory()
+ }
+}(this, function() {
+
+'use strict'
+
+/** @exports G */
+const G = {
+
+ clones: false,
+
+ /**
+ * Calculates a factorial
+ * @param {Number} n - The number to operate the factorial on.
+ * @returns {Number} n!
+ */
+ factorial: function factorial(n) {
+ for (var ans = 1; n; ans *= n--);
+ return ans
+ },
+
+ /**
+ * Converts a number to the factorial number system. Digits are in least significant order.
+ * @param {Number} n - Integer in base 10
+ * @returns {Array} digits of n in factoradic in least significant order
+ */
+ factoradic: function factoradic(n) {
+ let radix = 1
+ for (var digit = 1; radix < n; radix *= ++digit);
+ if (radix > n) radix /= digit--
+ let result = [0]
+ for (; digit; radix /= digit--) {
+ result[digit] = Math.floor(n / radix)
+ n %= radix
+ }
+ return result
+ },
+
+ /**
+ * Calculates the number of possible permutations of "k" elements in a set of size "n".
+ * @param {Number} n - Number of elements in the set.
+ * @param {Number} k - Number of elements to choose from the set.
+ * @returns {Number} n P k
+ */
+ P: function P(n, k) {
+ return this.factorial(n) / this.factorial(n - k)
+ },
+
+ /**
+ * Calculates the number of possible combinations of "k" elements in a set of size "n".
+ * @param {Number} n - Number of elements in the set.
+ * @param {Number} k - Number of elements to choose from the set.
+ * @returns {Number} n C k
+ */
+ C: function C(n, k) {
+ return this.P(n, k) / this.factorial(k)
+ },
+
+ /**
+ * Higher level method for counting number of possible combinations of "k" elements from a set of size "n".
+ * @param {Number} n - Number of elements in the set.
+ * @param {Number} k - Number of elements to choose from the set.
+ * @param {Object} [options]
+ * @param {Boolean} options.replace - Is replacement allowed after each choice?
+ * @param {Boolean} options.ordered - Does the order of the choices matter?
+ * @returns {Number} Number of possible combinations.
+ */
+ choices: function choices(n, k, options = {}) {
+ if (options.replace) {
+ if (options.ordered) {
+ return Math.pow(n, k)
+ } else {
+ return this.C(n + k - 1, k)
+ }
+ } else {
+ if (options.ordered) {
+ return this.P(n, k)
+ } else {
+ return this.C(n, k)
+ }
+ }
+ },
+
+ /**
+ * Generates all combinations of a set.
+ * @param {Array|String} arr - The set of elements.
+ * @param {Number} [size=arr.length] - Number of elements to choose from the set.
+ * @returns {Generator} yields each combination as an array
+ */
+ combination: function* combination(arr, size = arr.length) {
+ let that = this
+ let end = arr.length - 1
+ let data = []
+ yield* combinationUtil(0, 0)
+ function* combinationUtil(start, index) {
+ if (index === size) { // Current combination is ready to be processed, yield it
+ return yield that.clones ? data.slice() : data // .slice() is a JS idiom for shallow cloning an array
+ }
+ // replace index with all possible elements. The condition
+ // "end - i + 1 >= size - index" makes sure that including one element
+ // at index will make a combination with remaining elements
+ // at remaining positions
+ for (let i = start; i <= end && end - i + 1 >= size - index; i++) {
+ data[index] = arr[i]
+ yield* combinationUtil(i + 1, index + 1)
+ }
+ }
+ },
+
+ /**
+ * Generates all permutations of a set.
+ * @param {Array|String} arr - The set of elements.
+ * @param {Number} [size=arr.length] - Number of elements to choose from the set.
+ * @returns {Generator} yields each permutation as an array
+ */
+ permutation: function* permutation(arr, size = arr.length) {
+ let that = this
+ let len = arr.length
+ if (size === len) { // switch to Heap's algorithm. it's more efficient
+ return yield* heapsAlg(arr, that.clones)
+ }
+ let data = []
+ let indecesUsed = [] // permutations do not repeat elements. keep track of the indeces of the elements already used
+ yield* permutationUtil(0)
+ function* permutationUtil(index) {
+ if (index === size) {
+ return yield that.clones ? data.slice() : data
+ }
+ for (let i = 0; i < len; i++) {
+ if (!indecesUsed[i]) {
+ indecesUsed[i] = true
+ data[index] = arr[i]
+ yield *permutationUtil(index + 1)
+ indecesUsed[i] = false
+ }
+ }
+ }
+ },
+
+ /**
+ * Generates all possible subsets of a set (a.k.a. power set).
+ * @param {Array|String} arr - The set of elements.
+ * @returns {Generator} yields each subset as an array
+ */
+ powerSet: function* powerSet(arr) {
+ let that = this
+ let len = arr.length
+ let data = []
+ yield* powerUtil(0, 0)
+ function* powerUtil(start, index) {
+ data.length = index
+ yield that.clones ? data.slice() : data
+ if (index === len) {
+ return
+ }
+ for (let i = start; i < len; i++) {
+ data[index] = arr[i]
+ yield* powerUtil(i + 1, index + 1)
+ }
+ }
+ },
+
+ /**
+ * Generates the permutation of the combinations of a set.
+ * @param {Array|String} arr - The set of elements.
+ * @returns {Generator} yields each permutation as an array
+ */
+ permutationCombination: function* permutationCombination(arr) {
+ let that = this
+ let len = arr.length
+ let data = []
+ let indecesUsed = []
+ yield* permutationUtil(0)
+ function* permutationUtil(index) {
+ data.length = index
+ yield that.clones ? data.slice() : data
+ if (index === len) {
+ return
+ }
+ for (let i = 0; i < len; i++) {
+ if (!indecesUsed[i]) {
+ indecesUsed[i] = true
+ data[index] = arr[i]
+ yield *permutationUtil(index + 1)
+ indecesUsed[i] = false
+ }
+ }
+ }
+ },
+
+ /**
+ * Generates all possible "numbers" from the digits of a set.
+ * @param {Array|String} arr - The set of digits.
+ * @param {Number} [size=arr.length] - How many digits will be in the numbers.
+ * @returns {Generator} yields all digits as an array
+ */
+ baseN: function* baseN(arr, size = arr.length) {
+ let that = this
+ let len = arr.length
+ let data = []
+ yield* baseNUtil(0)
+ function* baseNUtil(index) {
+ if (index === size) {
+ return yield that.clones ? data.slice() : data
+ }
+ for (let i = 0; i < len; i++) {
+ data[index] = arr[i]
+ yield* baseNUtil(index + 1)
+ }
+ }
+ },
+
+ /**
+ * Infinite generator for all possible "numbers" from a set of digits.
+ * @param {Array|String} arr - The set of digits
+ * @returns {Generator} yields all digits as an array
+ */
+ baseNAll: function* permutationAll(arr) {
+ for (let len = 1; true; len++) {
+ yield* this.baseN(arr, len)
+ }
+ },
+
+ /**
+ * Generates the cartesian product of the sets.
+ * @param {...(Array|String)} sets - variable number of sets of n elements.
+ * @returns {Generator} yields each product as an array
+ */
+ cartesian: function* cartesian(...sets) {
+ let that = this
+ let data = []
+ yield* cartesianUtil(0)
+ function* cartesianUtil(index) {
+ if (index === sets.length) {
+ return yield that.clones ? data.slice() : data
+ }
+ for (let i = 0; i < sets[index].length; i++) {
+ data[index] = sets[index][i]
+ yield* cartesianUtil(index + 1)
+ }
+ }
+ },
+
+ /**
+ * Shuffles an array in place using the Fisher–Yates shuffle.
+ * @param {Array} arr - A set of elements.
+ * @returns {Array} a random, unbiased perutation of arr
+ */
+ shuffle: function shuffle(arr) {
+ for (let i = arr.length - 1; i > 0; i--) {
+ let j = Math.floor(Math.random() * (i + 1))
+ swap(arr, i, j)
+ }
+ return arr
+ }
+
+}
+
+
+let clone = { clones: true }
+clone.combination = G.combination
+clone.permutation = G.permutation
+clone.powerSet = G.powerSet
+clone.permutationCombination = G.permutationCombination
+clone.baseN = G.baseN
+clone.baseNAll = G.baseNAll
+clone.cartesian = G.cartesian
+
+G.clone = clone
+
+
+
+/*
+ * More efficient alorithm for permutations of All elements in an array. Doesn't
+ * work for "sub-permutations", e.g. permutations of 3 elements from [1, 2, 3, 4, 5]
+ */
+function* heapsAlg(arr, clone) {
+ let size = arr.length
+ if (typeof arr === 'string') {
+ arr = arr.split('')
+ }
+ yield* heapsUtil(0)
+ function* heapsUtil(index) {
+ if (index === size) {
+ return yield clone ? arr.slice() : arr
+ }
+
+ for (let j = index; j < size; j++) {
+ swap(arr, index, j)
+ yield* heapsUtil(index + 1)
+ swap(arr, index, j)
+ }
+ }
+}
+
+/*
+ * Swaps two array elements.
+ */
+function swap(arr, i, j) {
+ let len = arr.length
+ if (i >= len || j >= len) {
+ console.warn('Swapping an array\'s elements past its length.')
+ }
+ let temp = arr[j]
+ arr[j] = arr[i]
+ arr[i] = temp
+ return arr
+}
+
+
+return G
+
+}))
diff --git a/js/node_modules/generatorics/package.json b/js/node_modules/generatorics/package.json
new file mode 100644
index 0000000..a4ae899
--- /dev/null
+++ b/js/node_modules/generatorics/package.json
@@ -0,0 +1,39 @@
+{
+ "name": "generatorics",
+ "version": "1.1.0",
+ "description": "Efficient Combinatorics library for JavaScript using ES2015 generator functions. Generate power set, combination, and permutation.",
+ "main": "generatorics.js",
+ "engines": {
+ "node": ">=6.0.0"
+ },
+ "directories": {
+ "test": "test"
+ },
+ "dependencies": {},
+ "devDependencies": {
+ "chai": "^3.5.0",
+ "eslint": "^3.14.0",
+ "jsdoc-to-markdown": "^3.0.0",
+ "mocha": "^2.4.5"
+ },
+ "scripts": {
+ "lint": "eslint generatorics.js",
+ "test": "mocha",
+ "docs": "sed -n '/Documentation/q;p' README.md > README.bak.md; echo '## Documentation' >> README.bak.md; jsdoc2md generatorics.js >> README.bak.md && mv -f README.bak.md README.md"
+ },
+ "author": "Andrew Carlson ",
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/acarl005/generatorics.git"
+ },
+ "homepage": "https://github.com/acarl005/generatorics#readme",
+ "license": "MIT",
+ "keywords": [
+ "combinatorics",
+ "combination",
+ "permutation",
+ "powerset",
+ "factoradic",
+ "shuffle"
+ ]
+}
diff --git a/js/node_modules/generatorics/test/index.js b/js/node_modules/generatorics/test/index.js
new file mode 100644
index 0000000..e65e2be
--- /dev/null
+++ b/js/node_modules/generatorics/test/index.js
@@ -0,0 +1,529 @@
+var expect = require('chai').expect
+var G = require('../generatorics')
+
+describe('Arithmetic functions', () => {
+ it('factorial works', () => {
+ expect(G.factorial(0)).to.equal(1)
+ expect(G.factorial(1)).to.equal(1)
+ expect(G.factorial(2)).to.equal(2)
+ expect(G.factorial(3)).to.equal(6)
+ expect(G.factorial(4)).to.equal(24)
+ expect(G.factorial(5)).to.equal(120)
+ })
+
+ it('factoradic works', () => {
+ expect(G.factoradic(0)).to.eql([ 0 ])
+ expect(G.factoradic(1)).to.eql([ 0, 1 ])
+ expect(G.factoradic(2)).to.eql([ 0, 0, 1 ])
+ expect(G.factoradic(3)).to.eql([ 0, 1, 1 ])
+ expect(G.factoradic(100)).to.eql([ 0, 0, 2, 0, 4 ])
+ expect(G.factoradic(1337)).to.eql([ 0, 1, 2, 2, 0, 5, 1 ])
+ expect(G.factoradic(9001)).to.eql([ 0, 1, 0, 0, 0, 3, 5, 1 ])
+ expect(G.factoradic(3958174309503149571029856012)).to.eql([ 0, 1, 0, 2, 2, 3, 5, 5, 2, 2, 3, 7, 6, 1, 12, 14, 11, 12, 18, 0, 10, 2, 21, 12, 4, 21, 9 ])
+ })
+
+ it('P(n,r) works', () => {
+ expect(G.P(10, 3)).to.equal(720)
+ expect(G.P(10, 1)).to.equal(10)
+ expect(G.P(10, 0)).to.equal(1)
+ expect(G.P(10, 10)).to.equal(3628800)
+ })
+
+ it('C(n,r) works', () => {
+ expect(G.C(10, 3)).to.equal(120)
+ expect(G.C(10, 1)).to.equal(10)
+ expect(G.C(10, 0)).to.equal(1)
+ expect(G.C(10, 10)).to.equal(1)
+ })
+
+ it('higher level method for counting choices', () => {
+ expect(G.choices(10, 3, { replace: true, ordered: true })).to.equal(1000)
+ expect(G.choices(10, 3, { replace: true, ordered: false })).to.equal(220)
+ expect(G.choices(10, 3, { replace: false, ordered: true })).to.equal(720)
+ expect(G.choices(10, 3, { replace: false, ordered: false })).to.equal(120)
+ })
+})
+
+describe('Combinations', () => {
+ it('should get combinations of two from set of 3', () => {
+ var members = [
+ [ 1, 2 ],
+ [ 1, 3 ],
+ [ 2, 3 ]
+ ]
+ var answers = []
+ for (var comb of G.combination([1, 2, 3], 2)) {
+ answers.push(comb.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should work with size 1', () => {
+ var members = [
+ [ 1 ],
+ [ 2 ],
+ [ 3 ]
+ ]
+ var answers = []
+ for (var comb of G.combination([1, 2, 3], 1)) {
+ answers.push(comb.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should work with size 0', () => {
+ for (var comb of G.combination([1, 2, 3], 0)) {
+ expect(comb).to.eql([])
+ }
+ })
+
+ it('should yield nothing if size is greater than array length', () => {
+ for (var comb of G.combination([1, 2, 3], 4)) {
+ throw new Error('Made a combination when it should not have')
+ }
+ })
+
+ it('combinations should default to arr.length without size specified', () => {
+ for (var comb of G.combination([1, 2, 3])) {
+ expect(comb).to.eql([1, 2, 3])
+ }
+ })
+
+ it('should work with strings', () => {
+ var members = [
+ [ 'a', 'b' ],
+ [ 'a', 'c' ],
+ [ 'a', 'd' ],
+ [ 'b', 'c' ],
+ [ 'b', 'd' ],
+ [ 'c', 'd' ],
+ ]
+ var answers = []
+ for (var comb of G.combination('abcd', 2)) {
+ answers.push(comb.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('yields the same array each time', () => {
+ var arr = [...G.combination([1, 2, 3], 2)]
+ expect(arr).to.eql(Array(arr.length).fill(arr[0]))
+ })
+
+})
+
+describe('Permutations', () => {
+
+ it('should get permutations of 2 from a set of 3', () => {
+ var members = [
+ [ 1, 2 ],
+ [ 1, 3 ],
+ [ 2, 1 ],
+ [ 2, 3 ],
+ [ 3, 1 ],
+ [ 3, 2 ]
+ ]
+ var answers = []
+ for (var perm of G.permutation([1, 2, 3], 2)) {
+ answers.push(perm.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should work with size 1', () => {
+ var members = [
+ [ 1 ],
+ [ 2 ],
+ [ 3 ]
+ ]
+ var answers = []
+ for (var perm of G.permutation([1, 2, 3], 1)) {
+ answers.push(perm.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should work with size 0', () => {
+ for (var perm of G.permutation([1, 2, 3], 0)) {
+ expect(perm).to.eql([])
+ }
+ })
+
+ it('should yield nothing if size is greater than array length', () => {
+ for (var perm of G.permutation([1, 2, 3], 4)) {
+ throw new Error('Made a permutation when it should not have')
+ }
+ })
+
+ it('permutations should default to arr.length without size specified', () => {
+ var members = [
+ [ 1, 2, 3 ],
+ [ 1, 3, 2 ],
+ [ 2, 1, 3 ],
+ [ 2, 3, 1 ],
+ [ 3, 2, 1 ],
+ [ 3, 1, 2 ],
+ ]
+ var answers = []
+ for (var perm of G.permutation([1, 2, 3])) {
+ answers.push(perm.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should work with strings', () => {
+ var members = [
+ [ 'a', 'b' ],
+ [ 'a', 'c' ],
+ [ 'a', 'd' ],
+ [ 'b', 'a' ],
+ [ 'b', 'c' ],
+ [ 'b', 'd' ],
+ [ 'c', 'a' ],
+ [ 'c', 'b' ],
+ [ 'c', 'd' ],
+ [ 'd', 'a' ],
+ [ 'd', 'b' ],
+ [ 'd', 'c' ],
+ ]
+ var answers = []
+ for (var perm of G.permutation('abcd', 2)) {
+ answers.push(perm.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should work with string without specifying length', () => {
+ var members = [
+ [ 'a', 'b', 'c' ],
+ [ 'a', 'c', 'b' ],
+ [ 'b', 'a', 'c' ],
+ [ 'b', 'c', 'a' ],
+ [ 'c', 'b', 'a' ],
+ [ 'c', 'a', 'b' ]
+ ]
+ var answers = []
+ for (var perm of G.permutation('abc')) {
+ answers.push(perm.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('yields the same array each time', () => {
+ var arr = [...G.permutation([1, 2, 3], 2)]
+ expect(arr).to.eql(Array(arr.length).fill(arr[0]))
+ })
+
+})
+
+describe('Base N', () => {
+
+ it('should get number of 2 digits a set of 3', () => {
+ var members = [
+ [ 1, 1 ],
+ [ 1, 2 ],
+ [ 1, 3 ],
+ [ 2, 1 ],
+ [ 2, 2 ],
+ [ 2, 3 ],
+ [ 3, 1 ],
+ [ 3, 2 ],
+ [ 3, 3 ],
+ ]
+ var answers = []
+ for (var perm of G.baseN([1, 2, 3], 2)) {
+ answers.push(perm.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should work with size 1', () => {
+ var members = [
+ [ 1 ],
+ [ 2 ],
+ [ 3 ]
+ ]
+ var answers = []
+ for (var perm of G.baseN([1, 2, 3], 1)) {
+ answers.push(perm.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should work with size 0', () => {
+ for (var perm of G.baseN([1, 2, 3], 0)) {
+ expect(perm).to.eql([])
+ }
+ })
+
+ it('baseN should default to arr.length without size specified', () => {
+ var members = [
+ [ 1, 1, 1 ],
+ [ 1, 1, 2 ],
+ [ 1, 1, 3 ],
+ [ 1, 2, 1 ],
+ [ 1, 2, 2 ],
+ [ 1, 2, 3 ],
+ [ 1, 3, 1 ],
+ [ 1, 3, 2 ],
+ [ 1, 3, 3 ],
+ [ 2, 1, 1 ],
+ [ 2, 1, 2 ],
+ [ 2, 1, 3 ],
+ [ 2, 2, 1 ],
+ [ 2, 2, 2 ],
+ [ 2, 2, 3 ],
+ [ 2, 3, 1 ],
+ [ 2, 3, 2 ],
+ [ 2, 3, 3 ],
+ [ 3, 1, 1 ],
+ [ 3, 1, 2 ],
+ [ 3, 1, 3 ],
+ [ 3, 2, 1 ],
+ [ 3, 2, 2 ],
+ [ 3, 2, 3 ],
+ [ 3, 3, 1 ],
+ [ 3, 3, 2 ],
+ [ 3, 3, 3 ],
+ ]
+ var answers = []
+ for (var perm of G.baseN([1, 2, 3])) {
+ answers.push(perm.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('yields the same array each time', () => {
+ var arr = [...G.baseN([1, 2, 3])]
+ expect(arr).to.eql(Array(arr.length).fill(arr[0]))
+ })
+
+})
+
+
+describe('Power Set', () => {
+
+ it('should calculate power set', () => {
+ var members = [
+ [ ],
+ [ 1 ],
+ [ 2 ],
+ [ 1, 2 ],
+ [ 3 ],
+ [ 1, 3 ],
+ [ 2, 3 ],
+ [ 1, 2, 3 ]
+ ]
+ var answers = []
+ for (var sett of G.powerSet([1, 2, 3])) {
+ answers.push(sett.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('yields the same array each time', () => {
+ var arr = [...G.powerSet([1, 2, 3])]
+ expect(arr).to.eql(Array(arr.length).fill(arr[0]))
+ })
+
+})
+
+describe('Permutation Combination', () => {
+
+ it('should get the permutation of combinations', () => {
+ var members = [
+ [ ],
+ [ 'a' ],
+ [ 'b' ],
+ [ 'c' ],
+ [ 'a', 'b' ],
+ [ 'b', 'a' ],
+ [ 'a', 'c' ],
+ [ 'c', 'a' ],
+ [ 'b', 'c' ],
+ [ 'c', 'b' ],
+ [ 'a', 'b', 'c' ],
+ [ 'a', 'c', 'b' ],
+ [ 'b', 'a', 'c' ],
+ [ 'b', 'c', 'a' ],
+ [ 'c', 'a', 'b' ],
+ [ 'c', 'b', 'a' ]
+ ]
+ var answers = []
+ for (var comb of G.permutationCombination(['a', 'b', 'c'])) {
+ answers.push(comb.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should yield the same array each time', () => {
+ var arr = [...G.permutationCombination([1, 2, 3])]
+ expect(arr).to.eql(Array(arr.length).fill(arr[0]))
+ })
+
+})
+
+describe('Cartesian Product', () => {
+
+ it('should find the cartesian product of a bunch of arrays', () => {
+ var members = [
+ [0, 0, 0], [1, 0, 0], [2, 0, 0],
+ [0, 10, 0], [1, 10, 0], [2, 10, 0],
+ [0, 20, 0], [1, 20, 0], [2, 20, 0],
+ [0, 0, 100], [1, 0, 100], [2, 0, 100],
+ [0, 10, 100],[1, 10, 100],[2, 10, 100],
+ [0, 20, 100],[1, 20, 100],[2, 20, 100],
+ [0, 0, 200], [1, 0, 200], [2, 0, 200],
+ [0, 10, 200],[1, 10, 200],[2, 10, 200],
+ [0, 20, 200],[1, 20, 200],[2, 20, 200]
+ ]
+ var answers = []
+ for (var sett of G.cartesian([0, 1, 2], [0, 10, 20], [0, 100, 200])) {
+ answers.push(sett.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should work with apply', () => {
+ var members = [
+ [0, 0, 0], [1, 0, 0], [2, 0, 0],
+ [0, 10, 0], [1, 10, 0], [2, 10, 0],
+ [0, 20, 0], [1, 20, 0], [2, 20, 0],
+ [0, 0, 100], [1, 0, 100], [2, 0, 100],
+ [0, 10, 100],[1, 10, 100],[2, 10, 100],
+ [0, 20, 100],[1, 20, 100],[2, 20, 100],
+ [0, 0, 200], [1, 0, 200], [2, 0, 200],
+ [0, 10, 200],[1, 10, 200],[2, 10, 200],
+ [0, 20, 200],[1, 20, 200],[2, 20, 200]
+ ]
+ var answers = []
+ for (var sett of G.cartesian.apply(G, [[0, 1, 2], [0, 10, 20], [0, 100, 200]])) {
+ answers.push(sett.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should work with strings', () => {
+ var members = [
+ [ 'a', 'c', 'e' ],
+ [ 'a', 'c', 'f' ],
+ [ 'a', 'd', 'e' ],
+ [ 'a', 'd', 'f' ],
+ [ 'b', 'c', 'e' ],
+ [ 'b', 'c', 'f' ],
+ [ 'b', 'd', 'e' ],
+ [ 'b', 'd', 'f' ]
+ ]
+ var answers = []
+ for (var sett of G.cartesian('ab', 'cd', 'ef')) {
+ answers.push(sett.slice())
+ }
+ expect(answers).to.have.length(members.length)
+ expect(answers).to.deep.have.members(members)
+ })
+
+ it('should yield same array each time', () => {
+ var arr = [...G.cartesian('12', '34', '56')]
+ expect(arr).to.eql(Array(arr.length).fill(arr[0]))
+ })
+
+})
+
+
+describe('Infinite Base N', () => {
+
+ it('generates all permutations of an array', () => {
+ var members = [
+ [ 'a' ], [ 'b' ], [ 'c' ], [ 'a', 'a' ], [ 'a', 'b' ], [ 'a', 'c' ], [ 'b', 'a' ], [ 'b', 'b' ], [ 'b', 'c' ], [ 'c', 'a' ], [ 'c', 'b' ], [ 'c', 'c' ],
+ [ 'a', 'a', 'a' ], [ 'a', 'a', 'b' ], [ 'a', 'a', 'c' ], [ 'a', 'b', 'a' ], [ 'a', 'b', 'b' ], [ 'a', 'b', 'c' ], [ 'a', 'c', 'a' ], [ 'a', 'c', 'b' ],
+ [ 'a', 'c', 'c' ], [ 'b', 'a', 'a' ], [ 'b', 'a', 'b' ], [ 'b', 'a', 'c' ], [ 'b', 'b', 'a' ], [ 'b', 'b', 'b' ], [ 'b', 'b', 'c' ], [ 'b', 'c', 'a' ],
+ [ 'b', 'c', 'b' ], [ 'b', 'c', 'c' ], [ 'c', 'a', 'a' ], [ 'c', 'a', 'b' ], [ 'c', 'a', 'c' ], [ 'c', 'b', 'a' ], [ 'c', 'b', 'b' ], [ 'c', 'b', 'c' ],
+ [ 'c', 'c', 'a' ], [ 'c', 'c', 'b' ], [ 'c', 'c', 'c' ], [ 'a', 'a', 'a', 'a' ], [ 'a', 'a', 'a', 'b' ], [ 'a', 'a', 'a', 'c' ], [ 'a', 'a', 'b', 'a' ],
+ [ 'a', 'a', 'b', 'b' ], [ 'a', 'a', 'b', 'c' ], [ 'a', 'a', 'c', 'a' ], [ 'a', 'a', 'c', 'b' ], [ 'a', 'a', 'c', 'c' ], [ 'a', 'b', 'a', 'a' ], [ 'a', 'b', 'a', 'b' ],
+ [ 'a', 'b', 'a', 'c' ], [ 'a', 'b', 'b', 'a' ], [ 'a', 'b', 'b', 'b' ], [ 'a', 'b', 'b', 'c' ], [ 'a', 'b', 'c', 'a' ], [ 'a', 'b', 'c', 'b' ], [ 'a', 'b', 'c', 'c' ],
+ [ 'a', 'c', 'a', 'a' ], [ 'a', 'c', 'a', 'b' ], [ 'a', 'c', 'a', 'c' ], [ 'a', 'c', 'b', 'a' ], [ 'a', 'c', 'b', 'b' ], [ 'a', 'c', 'b', 'c' ], [ 'a', 'c', 'c', 'a' ],
+ ]
+ var nums = [ 'a', 'b', 'c' ]
+ var perms = []
+ var gen = G.baseNAll(nums)
+ for (var i = 0; i < 64; i++) {
+ perms.push(gen.next().value.slice())
+ }
+ expect(perms).to.eql(members)
+ })
+
+})
+
+
+describe('Clone submodule', () => {
+
+ it('clones combinations', () => {
+ var answers = []
+ for (var comb of G.combination([1, 2, 3], 2)) {
+ answers.push(comb.slice())
+ }
+ expect(answers).to.eql([...G.clone.combination([1, 2, 3], 2)])
+ })
+
+ it('clones permutations', () => {
+ var answers = []
+ for (var comb of G.permutation([1, 2, 3], 2)) {
+ answers.push(comb.slice())
+ }
+ expect(answers).to.eql([...G.clone.permutation([1, 2, 3], 2)])
+
+ answers = []
+ for (var comb of G.permutation([1, 2, 3])) {
+ answers.push(comb.slice())
+ }
+ expect(answers).to.eql([...G.clone.permutation([1, 2, 3])])
+ })
+
+ it('clones power sets', () => {
+ var answers = []
+ for (var comb of G.powerSet([1, 2, 3])) {
+ answers.push(comb.slice())
+ }
+ expect(answers).to.eql([...G.clone.powerSet([1, 2, 3])])
+ })
+
+ it('clones permutations of combinations', () => {
+ var answers = []
+ for (var comb of G.permutationCombination([1, 2, 3])) {
+ answers.push(comb.slice())
+ }
+ expect(answers).to.eql([...G.clone.permutationCombination([1, 2, 3])])
+ })
+
+ it('clones base N', () => {
+ var answers = []
+ for (var comb of G.baseN([1, 2, 3])) {
+ answers.push(comb.slice())
+ }
+ expect(answers).to.eql([...G.clone.baseN([1, 2, 3])])
+ })
+
+ it('clones cartesian products', () => {
+ var answers = []
+ for (var comb of G.cartesian([1, 2, 3], [5, 6], [1, 8])) {
+ answers.push(comb.slice())
+ }
+ expect(answers).to.eql([...G.clone.cartesian([1, 2, 3], [5, 6], [1, 8])])
+ })
+
+})
diff --git a/js/package-lock.json b/js/package-lock.json
new file mode 100644
index 0000000..ca02eab
--- /dev/null
+++ b/js/package-lock.json
@@ -0,0 +1,27 @@
+{
+ "name": "js",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "dependencies": {
+ "generatorics": "^1.1.0"
+ }
+ },
+ "node_modules/generatorics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/generatorics/-/generatorics-1.1.0.tgz",
+ "integrity": "sha1-aVBgu42IuQmzAXGlyz1CR2hmETg=",
+ "engines": {
+ "node": ">=6.0.0"
+ }
+ }
+ },
+ "dependencies": {
+ "generatorics": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/generatorics/-/generatorics-1.1.0.tgz",
+ "integrity": "sha1-aVBgu42IuQmzAXGlyz1CR2hmETg="
+ }
+ }
+}
diff --git a/js/package.json b/js/package.json
new file mode 100644
index 0000000..2e5b365
--- /dev/null
+++ b/js/package.json
@@ -0,0 +1,5 @@
+{
+ "dependencies": {
+ "generatorics": "^1.1.0"
+ }
+}