# How to code golf in Javascript

The goal of "code golf" is to reduce the size of a program as much as possible. It's a fascinating practice that I knew very little about. To change that, I recently challenged myself to code golf a simple Javascript program.

In this article I'm sharing the program I wrote, and the 6 main stages I went through to make it much shorter. This should give an overview of the main techniques used to code golf in Javascript.

## The starting point

The code I made for this challenge is using the canvas to draw a black square, and make it move from left to right. That's not very impressive, but that's enough for our purpose. ``````// Retrieve the canvas and its context
let canvas = document.getElementById('c');
let ctx = canvas.getContext('2d');

// Set the canvas size
canvas.width = 100;
canvas.height = 100;

// Variable to store the x position of the square
let x = 0;

// Main function that draws the square and moves it
loop();

function loop() {
// Clear the canvas, so we can draw on it later
ctx.clearRect(0, 0, canvas.width, canvas.height);

// Change the position of the square
if (x > canvas.width) {
// If it's gone too far, move it to the far left
x = -20;
} else {
// Otherwise, move it slightly to the right
x = x + 2;
}

// Draw the black square at the position x
ctx.fillRect(x, 20, 20, 20);

// Call the loop function about 60 times per second
requestAnimationFrame(loop);
}``````

Without comments, that's 344 characters. How short do you think it can become?

## Stage 1: the basics

• The keyword `let` is not mandatory in Javascript, so we remove it.
• We reduce the length of all variables names, for example `canvas` becomes `c`.
• In the `loop()` function, we replace `c.width` and `c.height` by their respective values: `100` and `100`.
• And we make the `if-else` shorter with a ternary operator.

Removing spaces, semicolons, and new lines will be done near the end to keep the code more readable for now.

With all these changes, the program looks like this.

``````c = document.getElementById('c');
t = c.getContext('2d');
c.width = 100;
c.height = 100;
x = 0;

loop();

function loop() {
t.clearRect(0, 0, 100, 100);
x = (x > 100) ? -20 : x + 2;
t.fillRect(x, 20, 20, 20);
requestAnimationFrame(loop);
}``````

Character count: from 344 to 247.

## Stage 2: DOM and canvas tricks

After some googling I discovered 3 tricks related to the DOM and the canvas that will make the code significantly shorter.

The first one is about `getElementById()`. It turns out it is not necessary to use this function at all, because Javascript automatically creates variables for each HTML elements with an id. So to access the canvas that has `id="c"`, we can directly use the variable `c`.

The second trick is about `requestAnimationFrame()`. This is a great function to refresh the canvas about 60 times per second, but it's also quite long to type. Instead we should call `setInterval()` that works pretty much the same, and is a lot shorter.

The last trick is about `clearRect()`. There is a way to clear the canvas without `clearRec()`: by setting the size of the canvas. So if we put `c.width = 100` directly inside the `loop()` function, the canvas will be cleared at every frame.

Here's the new code with the 3 tricks in place.

``````t = c.getContext('2d');
x = 0;

setInterval(loop, 20);

function loop() {
c.width = 100;
c.height = 100;
x = (x > 100) ? -20 : x + 2;
t.fillRect(x, 20, 20, 20);
}``````

And now that we are using `setInterval()`, let's replace `loop()` by an anonymous function.

``````t = c.getContext('2d');
x = 0;

setInterval(() => {
c.width = 100;
c.height = 100;
x = (x > 100) ? -20 : x + 2;
t.fillRect(x, 20, 20, 20);
}, 20);``````

Character count: from 247 to 154.

## Stage 3: smarter variables

If we use our variables in smarter ways, it's possible save a few characters. Here are some ideas:

• The first time the function `setInterval()` is called, it returns the value `1`. We can take advantage of that to directly initialize the variable `x` like this: `x = setInterval(...)`.
• It's possible to assign multiple variables at once. For example: `c.width = c.height = 100`.
• The variable `t` (the context of the canvas) is used only once when we do `t.fillRect(...)`. This means we don't need this variable, instead we directly write `c.getContext('2d').fillRect(...)`.
``````x = setInterval(() => {
c.width = c.height = 100;
x = (x > 100) ? -20 : x + 2;
c.getContext('2d').fillRect(x, 20, 20, 20);
}, 20);``````

And there are 2 more things we should do:

• We are using the number `20` 5 times in our code. We can avoid this repetition if we store `20` in a new variable called `k`.
• And let's apply the same idea on the number `100` that is used 2 times, and store it in a variable called `w`.

These 2 changes are actually making the code slightly longer. But soon, when we will remove spaces and semicolons, these modifications will become worthwhile.

``````k = 20;
x = setInterval(() => {
w = c.width = c.height = 100;
x = (x > w) ? -k : x + 2;
c.getContext('2d').fillRect(x, k, k, k);
}, k);``````

Character count: from 154 to 141.

## Stage 4: merge lines

When a variable is assigned in Javascript, the value of the variable itself is returned. For example, when doing `k = 20` we are setting `k` to `20` and we are also returning the value `20`. We can use this fact to combine two lines into one, like this.

``````// Before
k = 20;
x = setInterval(/* ... */, k);

// After
x = setInterval(/* ... */, k = 20);``````

With the same idea, we merge these two lines, and remove the variable `w`.

``````// Before
w = c.width = c.height = 100;
x = (x > w) ? -k : x + 2;

// After
x = (x > (c.width = c.height = 100)) ? -k : x + 2;``````

And also these two lines.

``````// Before
x = (x > (c.width = c.height = 100)) ? -k : x + 2;
c.getContext('2d').fillRect(x, k, k, k);

// After
c.getContext('2d').fillRect(x = (x > (c.width = c.height = 100)) ? -k : x + 2, k, k, k);``````

Now our anonymous function contains a single line of code.

``````x = setInterval(() => {
c.getContext('2d').fillRect(x = (x > (c.width = c.height = 100)) ? -k : x + 2, k ,k, k);
}, k = 20);``````

Character count: from 141 to 126.

## Stage 5: clean up

What we have so far is quite compact, yet there are some unecessary characters in it. Removing them won't change anything, expept making our code shorter. So we should:

• Remove a pair of parenthesis from the ternary operator that is not needed.
• Remove the two semicolons that are unnecessary.
• And remove all spaces and newlines, because they are all optional.
``x=setInterval(()=>{c.getContext('2d').fillRect(x=x>(c.width=c.height=100)?-k:x+2,k,k,k)},k=20)``

Character count: from 126 to 94.

## Stage 6: last tricks

There are 3 remaining tricks.

First, if we read closely the `setIterval()` documentation, we will discover that the callback parameter can either be a function or a string. So we replace `()=>{...}` by `"..."`, and win 4 chars.

Second, we should take advantage of the "tagged template" ES6 feature by changing `c.getContext('2d')` into `c.getContext`2d``. That's shorter by 2 chars.

And third, it's possible to change the number `100` into `99` to save one char.

Here is the final result:

``x=setInterval("c.getContext`2d`.fillRect(x=x>(c.width=c.height=99)?-k:x+2,k,k,k)",k=20)``

Character count: from 94 to 87.

The original code had 344 characters. Now it's about 4 times shorter for the same result!

## Bonus

We only talked about the Javascript so far, but what about the HTML?

Here's the code for both the HTML and the Javascript, in only 117 chars. I added some line breaks below only for legibility.

``````<canvas id=c>
<script>
x=setInterval("c.getContext`2d`.fillRect(x=x>(c.width=c.height=99)?-k:x+2,k,k,k)",k=20)
</script>``````

If you save this tiny program in an HTML file and open it in a browser, you will see this result. ## Conclusion

Going from 344 characters to just 87 was a fascinating journey. Multiple times I though "there's no way to be shorter", but I was always wrong. And there may be ways to make the code even smaller. The full source code of this project is available on GitHub.

It took me about a week of work and the help of a friend to get to the last solution. I learned a lot about Javascript with this challenge, and I hope you enjoyed reading about it!

If you have any questions or feedback: thomas@lesscake.com :-)