Perl Weekly Challenge 164.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 164.
Task 1: Prime Palindrome
Submitted by: Mohammad S Anwar
Write a script to find all prime numbers less than 1000, which
are also palindromes in base 10. Palindromic numbers are
numbers whose digits are the same in reverse. For example, 313
is a palindromic prime, but 337 is not, even though 733 (337
reversed) is also prime.
I guess one can generate primes and filter palindromes or the other way around. The former is straightforward:
perl -MMath::Prime::Util=primes -E 'say "Output: ", join ", ", grep {$_ eq reverse} @{primes(1000)}'
Results:
Output: 2, 3, 5, 7, 11, 101, 131, 151, 181, 191, 313, 353, 373, 383, 727, 757, 787, 797, 919, 929
I can check with the script included with Math::Prime::Util
:
primes.pl --palindr 1000|perl -E '$/=""; say "Output: ",join ", ", split "\n", <>'
Results:
Output: 2, 3, 5, 7, 11, 101, 131, 151, 181, 191, 313, 353, 373, 383, 727, 757, 787, 797, 919, 929
In full:
1 # Perl weekly challenge 164
2 # Task 1: Prime palindrome
3 #
4 # See https://wlmb.github.io/2022/05/12/PWC164/#task-1-prime-palindrome
5 use v5.12;
6 use warnings;
7 use Math::Prime::Util qw(primes);
8 say "Output: ", join ", ", grep {$_ eq reverse} @{primes(1000)};
Run the code:
./ch-1.pl
Results:
Output: 2, 3, 5, 7, 11, 101, 131, 151, 181, 191, 313, 353, 373, 383, 727, 757, 787, 797, 919, 929
Some variations could include allowing the user to set the range of numbers to test and the base (what’s so special about 10?).
Task 2: Happy Numbers
Submitted by: Robert DiCicco
Write a script to find the first 8 Happy Numbers in
base 10. For more information, please check out Wikipedia.
Starting with any positive integer, 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.
Example
19 is Happy Number in base 10, as shown:
19 => 1^2 + 9^2
=> 1 + 81
=> 82 => 8^2 + 2^2
=> 64 + 4
=> 68 => 6^2 + 8^2
=> 36 + 64
=> 100 => 1^2 + 0^2 + 0^2
=> 1 + 0 + 0
=> 1
I test each integer in sequence for happiness until I get 8 of them. To that end, I map integers to the sum of the squares of their digits and keep an array of seen numbers to detect cycles to finish the search. If I finish with a 1, I’ve found a happy number.
perl -MList::Util=sum -E '$n=0; for(1..8){while(1){ say($n),last if h(++$n)}}
sub h {$x=shift; my %s; while(!$s{$x}){$s{$x}=1;$x=sum map {$_*$_} split "", $x} return $x==1;}'
Results:
1
7
10
13
19
23
28
31
In full:
1 # Perl weekly challenge 164
2 # Task 2: Happy numbers
3 #
4 # See https://wlmb.github.io/2022/05/12/PWC164/#task-2-happy-numbers
5 use v5.12;
6 use warnings;
7 use List::Util qw(sum);
8 my $desired=8;
9 my $try=1;
10 my @found=();
11 while(@found<$desired){
12 push @found, $try if happy($try);
13 ++$try;
14 }
15 say "The first $desired happy numbers are: ", join " ", @found;
16
17 sub happy {
18 my $x=shift;
19 my %seen;
20 while(!$seen{$x}){
21 $seen{$x}=1;
22 $x=sum map {$_*$_} split "", $x
23 }
24 return $x==1;
25 }
Use:
./ch-2.pl
Results:
The first 8 happy numbers are: 1 7 10 13 19 23 28 31
Variations could include allowing the user to set the hapiness desired and the base to use.
It is interesting that there is always a cycle at the end of
the iteration so we don’t have to worry about infinite
iterations. For example, imagine we want to check if a
million-digit number is happy. As the squares of each digit
are at
most 81, the first iteration would yield at most 81,000,000,
an eight digit number. The next iteration would yield at most
648=8×81, a three digit number, and the following iterations
would all be bounded by 243=3×81. Thus, after a finite number of
steps one of the numbers 1…243 ought to be repeated,
initiating a cycle. Curiously, in base ten there are only two
possible cycles, 4 → 16 → 37 → 58 → 89 → 145 → 42 → 20 → 4 →
or 1 → 1 →. Thus, there is really no need for keeping
the %seen
array, yielding a slightly simpler solution:
perl -MList::Util=sum -E '$n=0; for(1..8){say($n), next if h(++$n); redo}
sub h {$x=shift; $x=sum map {$_*$_} split "", $x while($x != 4 && $x!=1); return $x==1;}'
I also changed the flow control, just for fun.
Results:
1
7
10
13
19
23
28
31