This blog post is also available on the Fortnox developer blog.
During the early 00s my programming was more or less about creating and maintaining web sites in LAMP setups. From that period I remember fighting many battles trying to make JavaScript code work across web browsers. It was not fun. For many years now I’ve kept my distance from the language, hoping for a better replacement to arrive at some point.
The thing is that JavaScript survived and is used extensively in all kinds of web setups, which is why I’ve decided to give the language another go. So I picked up JavaScript: The Good Parts (that have collected dust in a book shelf at home for several years) and saw this really nice presentation on functions in JavaScript recommended to me by a colleague at work. I read up on higher-order functions in the language and learned about some new stuff like arrow functions and constants (which are pretty cool). And then I decided to program something based on my understanding gained from all those resources.
My idea was to avoid the prototype stuff that I haven’t grasped fully yet and instead build something using functions and closures only. In the end I chose to build a simple snake game using JavaScript and React. Using React for a snake game is maybe overkill, but I found that the Create React App project gave me a nice bootstrapped environment for me to work in without the need to setup Babel, Webpack and all those other things you need to worry about. A few days in now there is a working version of the game that you can try here if you want. Just use the arrow keys or swipe to control the snake. Although the code is most probably far from idiomatic JavaScript, I decided to publish the code on GitHub, with the plan to ask some colleagues more experienced in the language to tell me what I’m doing wrong.
From this basic snake implementation I take with me a few insights. First, my time with the language was actually more pleasant than I had imagined. I believe that programming in Clojure and other functional programming languages have made me let go of the object-oriented paradigm a bit. This time around, when I decided to stick with using just functions and closures, the code felt more natural to write than when I tried to program like I do in Java.
Secondly, I miss working with persistent data structures and having robust ways to manage state changes. The ability to stay immutable takes away a lot of complexity not really related to the problem you want to solve and lets you instead focus on what’s important. You can get all this by simply using ClojureScript instead of JavaScript (as ClojureScript compiles to JavaScript) but I’ll save that subject for another post. 😉
A final and fun takeaway from this exercise is that the snake in a snake game can be modeled as a queue (along with a variable to control its growth when it feeds). Let’s have a look at how this works, starting with the algorithm to use each time the snake moves.
1. Push the next coordinate to the queue. 2a. If the grow variable is zero, then pop the first item from the queue. 2b. Else, decrease the grow variable by one.
Consider the following queue with x and y coordinates represented as tuples. JavaScript lacks both a tuple and a queue data type, so good old arrays will have to do.
let grow = 0; const queue = [[1,1], [2,1], [3,1]];
So above we have a queue with three coordinates representing the snake. In this example, the snake is facing right, which means that the front of the snake is at [3,1] and the end of the snake is at [1,1]. Let’s move the snake one step to the right. According to the above algorithm, we push the next coordinate to the queue, which means that the queue now looks like this:
queue.push([4,1]); // queue is now: [[1,1], [2,1], [3,1], [4,1]]
The grow variable is zero, so we pop off the first element like so::
queue.splice(); // queue is now: [[2,1], [3,1], [4,1]]
Alright, so now we have moved one step to the right! Let’s pretend that the snake found something to eat at [4,1], which means that the snake will grow. In the current version of the game, the snake grows by three whenever it eats, so we’ll increase the grow variable by three. Now, let’s move the snake to the right again. We first add [5,1] to the queue. This time, the grow variable is greater than zero, so we will not pop an item off the queue this time but rather reduce the grow variable by one. The outcome of the first movement we just described is shown below.
queue.push([5,1]); grow--; // grow is now: 2 // queue is now: [[2,1], [3,1], [4,1], [5,1]]
As the snake keeps on moving the grow variable will eventually be reduced to zero. When that happens, we will start popping items off the queue again whenever the snake moves. I hope you found the snake discussion super interesting and life changing. 😉 That’s all for today, until next time!