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.
Weekly Challenge #164
Those numbers for which this process end in 1 are happy numbers, while those numbers that do not end in 1 are unhappy numbers.
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…