Build a Snake Game in functional JavaScript - Part 1
Tags: functional, beginners, codenewbie, javascript
Published: 2020-04-13 20:19:33

If you are interested in reading this article in Spanish, check out my blog [The Developer's Dungeon](https://www.patferraggi.dev/blog/2020/apr/functional-snake-1/)

Hey guys, I hope you are doing well and learning some new skills while quarantined. If that is the case then you are in luck because today we are gonna finish our beloved _Snake Game_ written in functional _JavaScript_. If you haven't read the previous article you can do it [here](https://dev.to/patferraggi/build-a-snake-game-in-functional-javascript-part-0-3hbk).

In our previous article, we end up having the UI ready and a small model of our snake. Today we are gonna extend that and complete the game, let us start by getting rid of the ugly parts.

## Side Effects

__Every software needs to produce side effects. If side effects would be avoided there would be no proof that the program actually runs__. In our case, we have 2 types of side effects: 

- The output of the game (what you see on the screen)
- The internal state of the game that needs to be updated (the position of the snake, apple, etc)

Pure functional programming languages come with certain tools that help us handle this in an elegant way. _JavaScript_, on the other hand, doesn't have these tools, they can be added by using libraries like [Ramda Fantasy](https://github.com/ramda/ramda-fantasy), but in our case, we are gonna use an approach called `Functional Core Imperative Shell`, which basically says that we can treat our code as mostly functional by keeping everything pure in one place and everything that is not pure near to the boundaries of our software, if you want to read more about it you can check the original blog post [here](https://www.destroyallsoftware.com/screencasts/catalog/functional-core-imperative-shell)

So following that approach __I am gonna be very explicit about which parts of the game produce side effects and which ones don't__.

### The output of the game

This is our current 'UI' module

```javascript
const r = require("ramda");
const { intercalate, update } = require("./helper");

const createWorld = (rows, columns, state) => {
  const repeatDot = r.repeat(".");

  const map = r.map(r.thunkify(repeatDot)(rows), repeatDot(columns));

  return r.pipe(addSnake(state), addApple(state))(map);
};

const addSnake = (state) => r.pipe(...r.map(update("X"), state.snake));

const addApple = (state) => update("O")(state.apple);

const displayWorld = (matrix) => {
  console.clear();
  console.log(intercalate("\r\n", r.map(intercalate(" "), matrix)));
};

const display = r.curry((rows, columns, state) => {
  return r.pipe(createWorld, displayWorld)(rows, columns, state);
});

module.exports = {
  display,
};
```

if you check this code there is only one single place where we produce side effects and that is the 'displayWorld' procedure:

```javascript
const displayWorld = (matrix) => {
  console.clear();
  console.log(intercalate("\r\n", r.map(intercalate(" "), matrix)));
};
```

The rest of the code takes input and produces output, that's it.

### The internal state of the game that needs to be updated 

This is the `index.js` file where we start our game

```javascript
const COLUMNS = 15;
const ROWS = 15;
const SPEED = 125;
let uglyMutableState = initialState;

const displayState = display(COLUMNS, ROWS);

const runGameLoop = () => {
  setInterval(() => {
    displayState(uglyMutableState);
  }, SPEED);
};

runGameLoop();
```

As you can see here, we take the initial state of the game and then we have an interval that runs every few seconds and constantly displays the world of the game, __in the future here we will have to call the logic to create a new state based on the previous one and update our `uglyMutableState` variable__. We are gonna keep all the logic of the game pure and only modify this state variable from this file.

__In a functional programming language, we would do this with `Recursion` but since _JavaScript_ engines lack `Tail Call Optimization` doing this here would blow the stack almost immediately__, we would have to use some dirty hacks like returning functions over functions to avoid this problem, but I thought at this point it was easier to be pragmatic and just follow the approach mentioned previously.

## Getting input

Getting input is one of those things that is gonna modify our state, specifically the state that says where the snake should be moving.

```javascript
// index.js
const setupInput = () => {
  readline.emitKeypressEvents(process.stdin);
  process.stdin.setRawMode(true);
  process.stdin.on("keypress", (str, key) => {
    if (key.ctrl && key.name === "c") process.exit();

    const options = {
      UP: addMove(direction.NORTH),
      LEFT: addMove(direction.WEST),
      DOWN: addMove(direction.SOUTH),
      RIGHT: addMove(direction.EAST),
    };

    const move = options[key.name.toUpperCase()];
    uglyMutableState = move(uglyMutableState);
  });
};

// snake.js
const direction = {
  NORTH: point(0, -1),
  SOUTH: point(0, 1),
  WEST: point(-1, 0),
  EAST: point(1, 0),
};

const initialState = {
  snake: [point(4, 3)],
  apple: point(5, 5),
  move: direction.EAST,
};

const addMove = r.curry((direction, state) =>
  isValidMove(direction, state.move) ? { ...state, move: direction } : state
);

// Checks that the snake always moves forward and
// cannot switch to the opposite direction
const isValidMove = (direction, move) =>
  direction.x + move.x !== 0 && direction.y + move.y !== 0;

```

This function reads the key events and just adds a new direction to our mutable state, as you can see both `addMove` and `isValidMove` they don't mutate anything, `addMove` receives a state and produces a new one with the new direction of our snake, notice how we added a property called `move` to our initial state and how we modeled the directions using the point structure defined in the previous article.

## The snake

Now we want to calculate the place where the snake is gonna be on every interval of our game loop __AKA Moving the Snake__. So let's do that:

```javascript
const nextSnake = r.curry((cols, rows, state) => {
  return willCrash(cols, rows, state)
    ? initialState
    : {
        ...state,
        snake: willEat(nextHead(cols, rows, state), state.apple)
          ? [nextHead(cols, rows, state), ...state.snake]
          : [nextHead(cols, rows, state), ...r.dropLast(1, state.snake)],
      };
});
```

Imagine that we already defined all the functions used here, let's go one by one, first, we ask if the snake is gonna crash to any part of its body, if it does then we return the initial state so the game starts again, if it doesn't crash then we return a new state. Inside the new state, we check again, is the snake gonna eat the apple? if yes then we move the snake and add one more point in its head so the snake grows. If, on the other hand, the snake does not eat the apple, then we add one point on the snake's head and we remove one from the back to give the impression that the snake is moving without growing. Now let's take a look at those missing functions:

```javascript
const willEat = r.equals;
const willCrash = (cols, rows, state) =>
  r.find(r.equals(nextHead(cols, rows, state)))(state.snake);

const nextHead = (cols, rows, { move, snake }) =>
  point(
    modulo(cols)(r.head(snake).x + move.x),
    modulo(rows)(r.head(snake).y + move.y)
  );
```
`willEat` just checks if to objects are equal, so we can just pass in the ramda.js [equals](https://ramdajs.com/docs/#equals) using point-free notation.
`nextHead` is gonna take the head of the snake, and the current direction and just create one new point that is next to it. Here we use `modulo` so when the snake gets to one side of the map, it comes through the other.
`willCrash` checks if the new head of the snake is gonna match any point of the body.

## The apple

Now that the snake is moving we can verify if the snake's head is gonna eat the apple and if that is the case we generate a new state where the apple is in a new random position.

```javascript
const nextApple = r.curry((cols, rows, state) =>
  willEat(r.head(state.snake), state.apple)
    ? { ...state, apple: point(randomPos(cols), randomPos(rows)) }
    : state
);
```

This is another case were technically we are not doing functional programming, as `nextApple` will produce different apples given the same input using the function `randomPos`.

## Assembling our game logic

Now finally we have everything we need to assemble our game logic, how are we gonna do that? we are gonna __create a function that receives the current state and calculates the new one__ based on the functions we just defined.

```javascript
const step = r.curry((cols, rows, state) =>
  r.pipe(nextSnake(cols, rows), nextApple(cols, rows))(state)
);
```

As you can see, first we create the snake, then we create the apple, and we returned the calculated state. Now we have to call this from our impure index.js

```javascript
const COLUMNS = 15;
const ROWS = 15;
const SPEED = 125;
let uglyMutableState = initialState;

const setupInput = () => {
  readline.emitKeypressEvents(process.stdin);
  process.stdin.setRawMode(true);
  process.stdin.on("keypress", (str, key) => {
    if (key.ctrl && key.name === "c") process.exit();

    const options = {
      UP: addMove(direction.NORTH),
      LEFT: addMove(direction.WEST),
      DOWN: addMove(direction.SOUTH),
      RIGHT: addMove(direction.EAST),
    };

    const move = options[key.name.toUpperCase()];
    uglyMutableState = move(uglyMutableState);
  });
};

const displayState = display(COLUMNS, ROWS);
const nextState = step(COLUMNS, ROWS);

const runGameLoop = () => {
  setInterval(() => {
    displayState(uglyMutableState);
    uglyMutableState = nextState(uglyMutableState);
  }, SPEED);
};

setupInput();
runGameLoop();
```

Now you can see what I meant about our game state being impure, every loop we get the new state and update our mutable state inside our index. Let's check the final result, shall we? 

![gamerunning](https://media.giphy.com/media/j77lvKqWHyMQPhH1qL/giphy.gif)

That is one good looking game, right? :smile:

## Conclusion

This example has a few caveats. It is clear that we could have gone more functional if we wanted to. 

- We could have incorporated Algebraic Data Types from ramda-fantasy.
- Use functions everywhere by using r.merge instead of object destruction and r.ifElse instead of ternary operators
- Use hacks to allow proper recursion instead of using 'setInterval'
- Use Monads for IO

But I think that __the whole point of doing _JavaScript_ in a functional way is so that you don't feel the immediate pressure of doing everything as a language like _Haskell_ would force you to__ so overall I think it is a good way of practicing functional programming on a language that is not strictly functional.

I really hope you enjoyed this small tutorial, it was very hard in the beginning but slowly I think I start to understand the basics of functional programming, I hope you do too. If you liked this article please share and let me know down below in the comments. If you have any doubts or you need some help don't doubt contacting me.