I've decided I'm going to try blogging about my attempts at the Perl Weekly Challenge which I've been doing since it started. Generally I do my challenge in Raku the language formally known as Perl6.
This weeks challenge has a couple of fun parts. If you've not tried it yet you might want to come back after you have.
Challenge 1
So I'd seen a video on this before it's called the Josephus Problem so I knew there was a mathematical solution to it.... but I couldn't remember it.
As is often the way I went a bit above and beyond and worked out a function to give the survivor number for any number of swordsmen. My thinking about it was simple. Get a list of number from 1 to 50, take the first two from the front. The first survives the second is dead. Put the survivor at the end of the list. Repeat until you have 1 survivor :
#| Calculate the survivor of the swordsmen suicide pact
multi sub MAIN(
UInt $swords = 50, #= Number of swordsmen (default 50)
) {
my @men = [1..$swords];
while ( @men.elems > 1 ) {
my ( $alive, $dead ) = @men.splice(0,2);
@men.push($alive);
}
say "Survivor of $swords is number {@men[0]}";
}
With that I was able to run the test for lots of different value and worked out the mathematical solution. Given a number of swordsmen (s) we find p where p < s and p is a power of 2. Then the number of the survivor is the nth odd number where n = s - p.
For example for s = 50, p = 32 and n is the 18th odd number (indexed on 0) which is 37.
The code for this :
#| Calculate mathematically
multi sub MAIN(
"math",
UInt $swords = 50, #= Number of swordsmen
) {
my $low-power = (1,* * 2...*).first(* > $swords) div 2;
say "Survivor of $swords is number {(1,3,5...*)[$swords - $low-power]}";
}
Couple of fun uses of Raku sequences one to generate the powers of 2 and the second to generate the list of odd numbers.
Challenge 2
For challenge 2 I initially worked on the theory I'll look at every date between 2020-01-01 and 2999-12-31 and look for palindromes. Turns out... that's a lot of days (357937 to be exact) and it take a while. Even when you use .hyper
to thread the tests over multiple cores. But then I had a thought.
If I went through every month and day combination that's 12 x 31 (we'll worry about out of range values in a second) and that's only 372 to check. If we take the month and day and flip it to get a year if we can check it's valid and it's between our start and end dates.
#| Find the palendromic numbers (writen mmddyyy) between 2000-01-01 and 2999-01-01
sub MAIN() {
my sub df( Date $d) {
# Bleh American dates
sprintf "%02d%02d%04d", .month, .day, .year given $d;
}
constant START = Date.new(2000,1,1,formatter => &df);
constant END = Date.new(2999,12,31, formatter => &df);
my @out;
for (1..12) -> $month {
for (1..31) -> $day {
my $date;
my $year = sprintf( "%02d%02d", $month, $day ).flip;
try {
$date = Date.new($year,$month,$day,formatter => &df);
}
next unless $date;
next unless START <= $date <= END;
@out.push($date);
}
}
.say for @out.sort;
}
I hope that all makes sense. Feel free to drop a comment if you've got questions or thoughts.
Top comments (0)