PWC 164 › Happy Numbers

This post is part of a series on Mohammad Anwar’s excellent Weekly Challenge, where hackers submit solutions in Perl, Raku, or any other language, to two different challenges every week. (It’s a lot of fun, if you’re into that sort of thing.)

Task #2 this week comes to us from Robert DiCicco, and Robert demands happiness! Or at least numbers that are happy. Either way, I could use some right about now.

We are to find the first 8 Happy Numbers in base 10. To test whether a number is Happy:

replace the number by the sum of the squares of its digits, and repeat the process until the number equals 1 (where it will stay), or it loops endlessly in a cycle which does not include 1.

Those numbers for which this process end in 1 are happy numbers, while those numbers that do not end in 1 are unhappy numbers.

Weekly Challenge #164

If You’re Happy and You Know It `return 1`

Using the algorithm exactly as described above, the Perl code is straightforward:

```sub is_happy(_) {
my \$n = shift;

my %seen;
for (my \$c = \$n; \$c != 1; \$c = sum map { \$_*\$_ } split //, \$c) {
return if \$seen{\$c}++;
}

return 1
}
```

`\$_ * \$_` is an optimization I make reflexively. Computing powers (i.e., `\$_ ** 2`), even for integers, is relatively slow (~15% on my VM), so for squaring a number, I often write out the multiplication by hand. It’s faster and does not suffer any real lack of clarity.

I achieve the loop detection with the `%seen` hash. If a number comes up more than once, we are in a loop. We keep computing the sum of squares of the digits and stop when we detect a loop (Not Happy), or when we reach 1 (Happy).

Outputting the First `\$count` Happy Numbers

Our job would be a little easier if we were asked to output numbers below a given limit. But outputting the first n is not much harder. We’ll just loop until we’ve seen `\$count` Happy numbers:

```my \$count = pop // 8;

# Output the first \$count Happy Numbers
for (local \$_ = 1; \$count > 0 ; \$_++) {
next unless is_happy;
say;
\$count--;
}
```

The highlighted line gives us an increasing number (`\$_`), but the loop termination condition depends on another variable (`\$count`). As much as we love our `foreach`-style loops, sometimes the good old fashioned C-style `for ( ; ; )` loop is best!

I decided to prototype `is_happy(_)` for a bit of syntactic sugar. This was completely unnecessary, of course.

My complete solutions are on GitHub.

That’s it for Week #164! Tune in next week for some fun with graphics…