diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..1117462
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,91 @@
+# WebStorm
+.idea/
+
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# next.js build output
+.next
+
+# nuxt.js build output
+.nuxt
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
diff --git a/package.json b/package.json
new file mode 100644
index 0000000..ec95e04
--- /dev/null
+++ b/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "javascript-pyramid-solitaire-solver",
+  "version": "1.0.0",
+  "description": "A brute force solver for pyramid solitaire written in javascript",
+  "main": "solver.js",
+  "scripts": {
+    "test": "mocha"
+  },
+  "repository": {
+    "type": "git",
+    "url": "git+https://github.com/IgniparousTempest/javascript-pyramid-solitaire-solver.git"
+  },
+  "author": "Courtney Pitcher",
+  "license": "ISC",
+  "bugs": {
+    "url": "https://github.com/IgniparousTempest/javascript-pyramid-solitaire-solver/issues"
+  },
+  "homepage": "https://github.com/IgniparousTempest/javascript-pyramid-solitaire-solver#readme",
+  "devDependencies": {
+    "mocha": "^6.2.0"
+  }
+}
diff --git a/solver.js b/solver.js
index 04beb5e..68cae35 100644
--- a/solver.js
+++ b/solver.js
@@ -79,9 +79,18 @@ class MoveString {
     static resetStock() {return "Reset stock.";}
 }
 
-const GameStates = Object.freeze({"won": 1, "lost": 2, "inProgress": 3});
+const GameStates = Object.freeze({"won": true, "lost": false});
 
-function solve(pyramidArray, stockArray, stockIndex, remainingStocks, moveArray) {
+/**
+ * Solves a Pyramid solitaire game.
+ * @param pyramidArray The cards in the pyramid, starting in the top card. The cards are in left-to-right, then top-to-bottom order.
+ * @param stockArray The cards in the stock.
+ * @param stockIndex The index of the top stock card.
+ * @param remainingStocks The number of times the stock can be reset.
+ * @param moveArray The list of moves that have been made to get a deck in this configuration.
+ * @returns {*[]|[*, *]|[*, *]|[*, *]|[*, *]|*}
+ */
+function solve(pyramidArray, stockArray, stockIndex = 0, remainingStocks = 3, moveArray = []) {
     let newMoveArray = JSON.parse(JSON.stringify(moveArray));
     let pyramid = new Pyramid(pyramidArray);
 
@@ -197,5 +206,7 @@ function solve(pyramidArray, stockArray, stockIndex, remainingStocks, moveArray)
     }
 
     // This node was useless
-    return [GameStates.inProgress, moveArray];
+    return [GameStates.lost, moveArray];
 }
+
+exports.solve = solve;
diff --git a/test.js b/test.js
new file mode 100644
index 0000000..bf6b5a4
--- /dev/null
+++ b/test.js
@@ -0,0 +1,15 @@
+const assert = require('assert');
+const solver = require('./solver');
+
+const solvable_games = [
+    "4C 8C 6S 7H 4D 6C 8S JH 2S 8H 4H KC AS 6H KD 7D JS TH AH 8D 9D AD 9S QS 7S TC 2D 5C 2C 9C TD 5S QC AC KH 9H 3C 7C 3S 3H 2H JD 5H 4S 6D QD 3D KS QH JC TS 5D"
+];
+
+it('should solve known games', () => {
+    assert.equal(true, true);
+    solvable_games.forEach(function (i) {
+        const array = i.split(' ');
+        const result = solver.solve(array.slice(0, 28), array.slice(28, 52), 0, 3, []);
+        assert.equal(result[0], true);
+    });
+});