Perl Weekly Challenge 223.
My solutions (task 1 and task 2 ) to the The Weekly Challenge - 223.
Task 1: Count Primes
Submitted by: Mohammad S Anwar
You are given a positive integer, $n.
Write a script to find the total count of primes less than or equal to the given integer.
Example 1
Input: $n = 10
Output: 4
Since there are 4 primes (2,3,5,7) less than or equal to 10.
Example 2
Input: $n = 1
Output: 0
Example 3
Input: $n = 20
Output: 8
Since there are 4 primes (2,3,5,7,11,13,17,19) less than or equal to 20.
I go for the canned solution using Math::Prime::Util
which has the
function prime_count
. This yields a very simple oneliner:
perl -MMath::Prime::Util=prime_count -E '
say "There are ", prime_count($_), " primes below $_" for @ARGV
' 10 20 100000
Results:
There are 4 primes below 10
There are 8 primes below 20
There are 9592 primes below 100000
The full code follows:
1 # Perl weekly challenge 223
2 # Task 1: Count Primes
3 #
4 # See https://wlmb.github.io/2023/06/27/PWC223/#task-1-count-primes
5 use v5.36;
6 use Math::Prime::Util qw(prime_count);
7 die <<~"FIN" unless @ARGV;
8 Usage: $0 N1 [N2...]
9 to find out how many primes there are upto N1, N2...
10 FIN
11 say "There are ", prime_count($_), " primes below $_" for @ARGV;
Example:
./ch-1.pl 10 20 100000
Results:
There are 4 primes below 10
There are 8 primes below 20
There are 9592 primes below 100000
Task 2: Box Coins
Submitted by: Mohammad S Anwar
You are given an array representing box coins, @box.
Write a script to collect the maximum coins until you took out all boxes.
If we pick box[i] then we collect the coins $box[i-1] * $box[i] * $box[i+1].
If $box[i+1] or $box[i-1] is out of bound then treat it as 1 coin.
Example 1:
Input: @box = (3, 1, 5, 8)
Output: 167
Step 1: pick box [i=1] and collected coins 3 * 1 * 5 => 15. Boxes available (3, 5, 8).
Step 2: pick box [i=1] and collected coins 3 * 5 * 8 => 120. Boxes available (3, 8).
Step 3: pick box [i=0] and collected coins 1 * 3 * 8 => 24. Boxes available (8).
Step 4: pick box [i=0] and collected coins 1 * 8 * 1 => 8. No more box available.
Example 2:
Input: @box = (1, 5)
Output: 10
Step 1: pick box [i=0] and collected coins 1 * 1 * 5 => 5. Boxes available (5).
Step 2: pick box [i=0] and collected coins 1 * 5 * 1 => 5. No more box available.
I assume all boxes have positive integers. My first guess was to pick the box with the smallest number at each step, so that upon deleting it, boxes with larger numbers come together and multiply themselves. Nevertheless, the boxes at the extremes are bounded by virtual boxes with only one coin which cannot be deleted, so I guess it is best not to choose the boxes at the extremes (as any factor would not be worse than 1), unless there is no alternative. This yields a three liner, which I explain in the full code below.
Exapmle 1:
perl -MList::UtilsBy=min_by -E '
@x=(1,@ARGV,1); $t+=$c while(defined ($c=n())); say "@ARGV -> $t";
sub n(){return if @x==2; return splice @x,1,1 if @x==3; $i=min_by {$x[$_]} @x==4?(1,2):(2..@x-3);
$v=splice @x,$i,1; return $v*$x[$i-1]*$x[$i]}
' 3 1 5 8
Results:
3 1 5 8 -> 167
Exapmle 2:
perl -MList::UtilsBy=min_by -E '
@x=(1,@ARGV,1); $t+=$c while(defined ($c=n())); say "@ARGV -> $t";
sub n(){return if @x==2; return splice @x,1,1 if @x==3; $i=min_by {$x[$_]} @x==4?(1,2):(2..@x-3);
$v=splice @x,$i,1; return $v*$x[$i-1]*$x[$i]}
' 1 5
Results:
1 5 -> 10
The full code follows:
1 # Perl weekly challenge 223
2 # Task 2: Box Coins
3 #
4 # See https://wlmb.github.io/2023/06/27/PWC223/#task-2-box-coins
5 use v5.36;
6 use List::UtilsBy qw(min_by);
7 die <<~"FIN" unless @ARGV;
8 Usage: $0 N1 [N2...]
9 to collect the maximum amount of coins from boxes with N1 N2... coins
10 FIN
11 my @extended=(1,@ARGV,1); # input args with guards on either side
12 my $total;
13 my $amount;
14 $total += $amount while(defined ($amount=next_amount())); # pick coins while they last
15 say "@ARGV -> $total";
16
17 sub next_amount(){ # choose a box and compute coins
18 return if @extended==0+2; # no more boxes, the 2 comes from the boundary guards
19 return splice @extended,1,1 if @extended==3; # only one box
20 my $i=min_by {$extended[$_]} # choose smallest box
21 @extended==2+2
22 ?(1,2) # only two remaining boxes, consider boundaries
23 :(2..@extended-3); # more boxes, disregard boundaries
24 my $value=splice @extended,$i,1; # remove box from array
25 return $value*$extended[$i-1]*$extended[$i]; # compute value from neighbor boxes
26 }
Example:
./ch-2.pl 3 1 5 8
./ch-2.pl 1 5
Results:
3 1 5 8 -> 167
1 5 -> 10
To allow numbers below 1, I would have to add code to consider the extremes if they are smaller than 1, and to ignore them if they are larger.