Perl Weekly Challenge: Week 91

Advent of Code update: I'm starting to fall behind. I'm still determined to finish it though. If you like, you can see my Raku solutions here. Thankfully, this weeks challenge wasn't very difficult; read on:

This weeks challenges:

Challenge 1:

Count Number

You are given a positive number $N.

Write a script to count number and display as you read it.

Example 1
Input: $N = 1122234
Output: 21321314

as we read "two 1 three 2 one 3 one 4"
Example 2
Input: $N = 2333445
Output: 12332415

as we read "one 2 three 3 two 4 one 5"
Example 3
Input: $N = 12345
Output: 1112131415

as we read "one 1 one 2 one 3 one 4 one 5"

All we need to do here is to split the input number $N into digits and traverse the resulting array. When a consecutive run of a particular digits ends and another begins, we print out the count and which number it was.

There needs to be special handling for the start i.e. when there is no range and $current is 0, and the very end which we deal with by adding an extra print() outside the loop.

This is the Perl version:

my $N = shift // die "Need a positive number.\n";

my $current = 0;
my $count = 0;

for my $i (split //, $N) {
    if ($i == $current) {
        $count++;
    } else {
        if ($current != 0) {
            print "$count$current";
        }
        $current = $i;
        $count = 1;
    }
}

print "$count$current\n";

(Full code on Github.)

...and this is Raku. For fun, I decided not to just port the Perl version. Instead I used the .classify() method. This gives us a hash where the keys are the number of unique digits and the values are arrays of each time they occurred in $N. So we can sort the keys of this hash and print the count of each value and then its key and get the right answer.

Well, we will get the right answer if the digits in $N are in ascending order as in the examples given with the problem. But later, it occurred to me that it will go wrong if this condition isn't met. Take 221112 for instance. We should output 223112 (and the Perl version gets it right) but instead we get 3132. Which just goes to show you the value of a comprehensive test suite!

sub MAIN(
    Int $N  #= a positive number.
) {
    my %count = $N.comb.classify({ $_; });

    for %count.keys.sort -> $k {
        print %count{$k}.elems, $k;
    }

    print "\n";
}

(Full code on Github.)

Challenge 2:

Jump Game

You are given an array of positive numbers @N, where value at each index determines how far you are allowed to jump further.

Write a script to decide if you can jump to the last index. Print 1 if you are able to reach the last index otherwise 0.

Example 1
Input: @N = (1, 2, 1, 2)
Output: 1

as we jump one place from index 0 and then twoe places from index 1 to reach the last index.
Example 2
Input: @N = (2,1,1,0,2)
Output: 0

it is impossible to reach the last index. as we jump two places from index 0 to reach index 2, followed by one place jump from index 2 to reach the index 3. once you reached the index 3, you can't go any further because you can only jump 0 position further.

We have a variable $current which stores which element of @N we are on. Then we keep incrementing $current by the value of the $current element. Now there are four possible outcomes.

$current is not at the last element of @N. In that case we do the increment thing again.

The value of the $current element is 0. Then we have to exit with a 0 because we cannot move any further so we would be stuck in an infinite loop.

If none of the previous conditions hold true, we are guaranteed to be at the last element so we can exit the loop and return 1.

This is the Perl implementation:

sub jump {
    my @N = @_;
    my $current = 0;

    while ( $current < (scalar @N - 1)) {
        $current += $N[$current];
        if ($N[$current] == 0 || $current > scalar @N) {
            return 0;
        }
    }

    return 1;
}

say jump(@ARGV);

(Full code on Github.)

...and this is Raku:

sub jump(@N) {
    my $current = 0;

    while $current < @N.elems - 1 {
        $current += @N[$current];
        if @N[$current] == 0 || $current >= @N.elems {
            return 0;
        }
    }

    return 1;
}

sub MAIN(
    *@N  #= a positive number.
) {
    say jump(@N);
}

(Full code on Github.)