JavaScript/Higher-order programming/Example 3

From Spherical
Revision as of 00:44, 15 June 2013 by Apollolux (talk | contribs) (created)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Here's a bunch of enemies we're fighting against:

var enemies = [
  {name: "Duck", hp: 10},
  {name: "Duck", hp: 10},
  {name: "Goose", hp: 15}
];

Let's kill them off:

forEach(enemies, function (enemy) {
   enemy.hp = 0;
});

Now they're all dead.

Our problem is to find out when every enemy's HP has dropped to zero.

The chump's way

var allDead = true;
for (var i = 0; i < enemies.length; ++i) {
  if (enemies[i].hp > 0)
    allDead = false;
}

This presents another problem which isn't in the previous example: what if the variable i is being used for something? Battle systems tend to occur in loops, and for all we know, that loop could be using i. We could shift onto variable j, and then future code changes would move into variable k... and it goes on. What a mess.

Another problem was developing the algorithm itself: I had to stop and think, how should I do this?

  1. Should allDead start false and turn into true when going through the loop and discovering all enemies are dead?
  2. Should allDead start true and turn into false when discovering a single living enemy?

I got side-tracked by the "how", and lost sight of the "what".

A smarter way

We could take advantage of our higher-order functions to express our intent more clearly:

var allDead = filter(function (enemy) {
  return enemy.hp > 0;
}, enemies).length === 0;

This is easy to read: we filter through all enemies to get all the living ones in an array. If the length of that array is 0, they're all dead. Again, shorter and a lot easier to read.

Note also that it expresses what I was after: all enemies are dead if the length of living enemies found is zero.