Sorting Tables Using KnockoutJS

I recently came up with a useful method for sorting tables using KnockoutJS that I felt was worth sharing. Supporting sorting of a grid/table is a pretty common feature you see on the web. However, most implementations are using an AJAX callback (or sometimes a full postback) to request the data in the desired sort pattern. The example I outline here uses KnockoutJS’ client side data binding and dependency tracking to sort efficiently without extra trips to the server. (See Demo)

Setting up the ViewModel

There are two key object properties on the viewmodel that make the sorting possible: columns (self.columns) and data (self.players). Since we are using KnockoutJS, both of the objects are instances of observableArrays:

// Observable array that represents each column in the table
self.columns = ko.observableArray([
    { property: "firstName", header: "First Name", type: "string", state: ko.observable("") },
    { property: "lastName", header: "Last Name", type: "string", state: ko.observable("") },
    { property: "dob", header: "Date of Birth", type: "date", state: ko.observable("") },
    { property: "wsWon", header: "World Series Championships", type: "number", state: ko.observable("") },
    { property: "stats.hr", header: "Home Runs", type: "object", state: ko.observable("") },
    { property: "stats.avg", header: "Batting Average", type: "object", state: ko.observable("") }
]);

// Observable array that will be our data
self.players = ko.observableArray([
    { firstName: "Micky", lastName: "Mantle", dob: "10/20/1931", wsWon: "7", stats: { hr: "536", avg: ".298" } },
    { firstName: "Ken", lastName: "Griffey Jr.", dob: "11/21/1969", wsWon: "0", stats: { hr: "630", avg: ".284" } },
    { firstName: "Derek", lastName: "Jeter", dob: "6/26/1974", wsWon: "5", stats: { hr: "260", avg: ".310" } },
    { firstName: "Lenny", lastName: "Dykstra", dob: "2/10/1963", wsWon: "1", stats: { hr: "81", avg: ".285" } },
    { firstName: "Ty", lastName: "Cobb", dob: "12/18/1886", wsWon: "0", stats: { hr: "117", avg: ".367" } }
]);

Notice how each object in the self.columns observable array has a key “property” that’s value corresponds to a key (or in some cases a child object and key) in the object that makes of the observable array of self.players. It is this relationship that we will capitalize on.

Binding Data in the View

In the view, we use two separate KnockoutJS “foreach” data binds to define our table. The first in the table header that builds the headers for each column. The second in the table body that fills the table body with rows of data:

After the bindings are applied (and a little Twitter Bootstrap CSS) the output in the browser looks like this:Sortable Table

Performing Sorts for Different Data Types

One of key features in this implementation is ability to sort different data types. JavaScript’s Array.sort method is a handy feature (read more about it here) of the language but unfortunately needs different compare functions for different data types. Below are the different sorts based on data type:

 // Generic sort method for numbers and strings
 self.stringSort = function (column) { // Pass in the column object

     self.players(self.players().sort(function (a, b) {

         // Set strings to lowercase to sort in a predictive way
         var playerA = a[column.property].toLowerCase(), playerB = b[column.property].toLowerCase();
         if (playerA < playerB) {
             return (column.state() === self.ascending) ? -1 : 1;
         }
         else if (playerA > playerB) {
             return (column.state() === self.ascending) ? 1 : -1;
         }
         else {
             return 0
         }
     }));
 };

 // Sort numbers
 self.numberSort = function (column) {
     self.players(self.players().sort(function (a, b) {

         var playerA = a[column.property], playerB = b[column.property];
         if (column.state() === self.ascending) {
             return playerA - playerB;
         }
         else {
             return playerB - playerA;
         }
     }));
 };

 // Sort by date
 self.dateSort = function (column) {

     self.players(self.players().sort(function (a, b) {

         if (column.state() === self.ascending) {
             return new Date(a[column.property]) - new Date(b[column.property]);
         }
         else {
             return new Date(b[column.property]) - new Date(a[column.property]);
         }
     }));
 };

 // Using a deep get method to find nested object properties
 self.objectSort = function (column) {

     self.players(self.players().sort(function (a, b) {

         var playerA = self.deepGet(a, column.property),
         playerB = self.deepGet(b, column.property);

         if (playerA < playerB) {
             return (column.state() === self.ascending) ? -1 : 1;
         }
         else if (playerA > playerB) {
             return (column.state() === self.ascending) ? 1 : -1;
         }
         else {
             return 0
         }
     }));
 };

See the Code In Action

To see this example in action please check out the demo. The full code is also available on GitHub.

Microsoft .NET is Fighting “The Man”

"I'd rather be fighting the man"

I know it sounds crazy. How is Microsoft .NET fighting “The Man”? Isn’t Microsoft “The Man”? After all, Windows PCs dominate market share almost 4:1. Licensing costs for their software and operating systems seem criminal at at times. The Microsoft .NET framework is “old and crusty” and no self respecting developer, especially those under the age of 40, dare acknowledge it has any redeeming value. (Side note: don’t trust anyone over 30.)

Pretty simple right? WRONG.

.NET == .ORG // returns true

In case you missed it, back in November, Microsoft made a big announcement: The Microsoft .NET framework was going open source – It’s core was on GitHub. That’s a pretty big deal. This means now that not only can anyone be a part of contributing to the framework, you could even fork an individual piece of the core and adapt it to suit an an individual application’s needs. There are evens plans to make the core, as well as ASP.NET, run on Mac and Linux.
This seems to have been a pretty big success. From what I have gleaned from social media, both the Microsoft and open source communities are excited and have welcomed this transition with open arms. As someone who has not been involved with the open source community but has worked mainly in the Microsoft technology stack, this has opened up a whole new world for me.

Free IDE

In addition to the open source announcement, Microsoft also announced a new professional grade IDE, Visual Studio Community Edition. Unlike previous free versions of Visual Studio, namely the Express family, Visual Studio Community Edition is as full featured as Visual Studio Professional Edition and doesn’t carry the $300 price tag. The barrier of entry to really dig into Microsoft .NET development is gone.

One of reasons I have always stuck around the Microsoft stack for software development is in part because of how good of an IDE Visual Studio is. Unlike most IDEs it can be used for a wide variety of languages and technologies that users can create solutions from. It also does a great job providing a consistent experience throughout this diverse mix. The impact of providing this for free shouldn’t be understated.

The Microsoft .NET Disruption

So what does this all mean? To me, it’s disruption of bias. That is what fighting the man is all about. It means informed software developers can no longer discount .NET solutions as viable options because of platform (http://www.omnisharp.net) or cost. It puts the focus back on writing good software. Even more so, having .NET maintained by both an enterprise and a powerful consuming community has the potential for a lot of great things to come.

Power to the people.

Creating a First Person Javascript 3D Maze

first person javascript based maze

Sometime ago, I came across a post by Hunter Loftis titled A First Person Engine in 265 Lines. I got pretty excited. Using a technique called raycasting, Loftis implemented a first person javascript engine that could seemingly render a 3D experience in the browser with ease. As a followup to this, I decided I wanted to a shot at extending the concept and have created aMaze (see demo).

About the Game

aMaze-screenshot2The game concept in aMaze is fairly straight forward. Users begin levels at a set point in the maze and need to “escape”. Their coordinates in the maze and cardinal (compass) direction they are facing are all they have to help guide themselves to “freedom”. Each level’s maze is setup completely different and can vary in size and complexity. Because of this complexity, I’ve added the ability for users to restart levels incase they get too lost. I’ve also added a bookmarking feature that continuously captures and stores location and direction so users can come back at anytime and not lose their progress.

Creating a Maze

Not surprisingly, one of the most enjoyable pieces of this puzzle has been creatings the mazes. Each maze/level in aMaze is a simple javascript object with a number of properties. I’ve tried to use the dynamic nature of javascript to allow for configuration as much as possible.

define([], function () {
    var level = {
        id: 4,
        startingPoint: { x: 2, y: 11 },
        startingDirection: 6.2831853, // East
        size: 48,
        wallTexture: { path: "assets/brick_texture.jpg", width: 700, height: 524 },
        walls: [
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 0, 1, 1, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 1, 1, 1, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 1, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
        ]
    };

    return level;
});

javascript array in excelThe key to this object is the walls property. It is a simple array containing 1s and 0s that represents walls and no walls. This is how the raycasting knows where to draw a wall and where not to.

As you can imagine, designing a maze with 1s and 0s in a text editor can be a little challenging. To make things easier, I am using Excel with some conditional formatting to give me a visual guide. With this method, it is much easier to conceptualize each maze. When I am satisfied with the design, I can simply copy the cells and paste their contents into javascript.

Initializing the Game

To bring the different pieces together I am utilizing require.js and the AMD approach. This allows for more modularity and organization of code and allows for cleaner markup. The HTML page that the game lives on is actually very basic.

<script src="scripts/require.min.js" async="" data-main="scripts/app.min"></script>
<div id="instructions"></div>
<div id="game-meta">
<div id="currentLevel"></div>
<div id="position"></div>
<input id="restartLevel" type="button" value="Level Restart" /> <input id="restartGame" type="button" value="Game Restart" />
</div>

Once app.min.js is loaded and it’s dependent modules are ready, the game is initialized and users can begin exploring. As mentioned earlier, each level is derived from a small (~3kb) minified javascript file. Using the AMD approach, I combine each each level into a single module on initialization and they are kept in memory. This means that the entire game and each level loaded in the client browser with a surprisingly small footprint. Pretty cool right?

Want to See/Learn More?

If you would like to see more, check out the demo and explore! I would also encourage you to fork this repo on GitHub.

In addition, a big shout out to Hunter Loftis for doing a lot of the heavy lifting going on here. He has some really cool demos available in the playfuljs-demos repo on GitHub.