Heart Attack - 1k Tower Defense

Defend your heart against waves of skulls by building a maze of towers but without blocking the way completely. Regular towers cost $2 and attack one enemy at a time but you can buy two upgrades to double their power ($3) and hit all enemies near by ($6). Letting eight skulls into your heart ends the game.


Source: “readable”, minified, compressed.


Minification Basics

The demo code is minified in two steps. First, one script replaces variable names longer than one byte and removes whitespace and comments. Then, a packing script replaces commonly used substrings with characters that don't appear in the minified program. The dictionary and code required to unpack the source is included in the final demo. The final version was created with First Crush but I used my own script for testing that displays more information about what's been replaced and I added one additional optimization from JSCrush by hand.

Game Basics

The path that the enemies take is determined by the placement of the towers and has to be calculated again each time a tower is added or removed. The genMap function implements a simplified version of Dijkstra's algorithm. Starting from the heart, it does a breadth-first search for the shortest way to every square on the board. The resulting directions for the creeps are stored in dir. Each element in this array points to the next square on the shortest way to the heart (e.g. {x:0,y:1} for “walk east”).

For every enemy, the game remembers only the position on the board. To animate the movement, the direction is added to the position multiplied by the current animation step. After 32 steps, the enemy is moved to the next square. That's why an enemy jumps if you put a tower directly in front of it. Its position on the board doesn't change but it has to walk a different path.

In every step, a list is generated for each tower of enemies that are within a Euclidean distance of 2 squares or less. Regular towers shoot only at the first in the list while upgraded towers hit all.

How to pack 1566 bytes into 1k

The size of the minified demo is 1566 bytes that's 542 more than in the final version which also includes the code for unpacking. To optimize the demo for packing requires to things: reusing as many strings as possible while using as few characters as possible. For instance, shift is both the Array function and part of shiftKey. Using the shift key for selling towers was cheap because I already used shift/pop for my search queue. Here are some more examples for packer-friendly programming™.

Is that even legal?

Even with a great packer you still have to use Javascript in creative and rule-bending ways. Here are some of my favorite insanities.