## Advent Calendar - December 16, 2022

Friday, Dec 16, 2022| Tags: Perl, Raku ### |   Day 15   |   Day 16   |   Day 17   |

The gift is presented by `Jaldhar H. Vyas`. Today he is talking about his solution to “The Weekly Challenge - 188”. This is re-produced for Advent Calendar 2022 from the original post by him.

## Challenge 1: Divisible Pairs

You are given list of integers `@list` of size `\$n` and divisor `\$k`.

Write a script to find out count of pairs in the given list that satisfies the following rules.

``````The pair (i, j) is eligible if and only if
a) 0 <= i < j < len(list)
b) list[i] + list[j] is divisible by k
``````

#### Example 1

``````Input: @list = (4, 5, 1, 6), \$k = 2
Output: 2
``````

#### Example 2

``````Input: @list = (1, 2, 3, 4), \$k = 2
Output: 2
``````

#### Example 3

``````Input: @list = (1, 3, 4, 5), \$k = 3
Output: 2
``````

#### Example 4

``````Input: @list = (5, 1, 2, 3), \$k = 4
Output: 2
``````

#### Example 5

``````Input: @list = (7, 2, 4, 5), \$k = 4
Output: 1
``````

In `Raku` this problem can be solved as a one-liner but I’ve chosen to spread it out a bit for clarity.

I found the way condition a in the spec is described to be a little unclear; what it actually means is that the values of `i` and `j` range between 0 and the size of the list.

``````(0 ..^ @list.elems)
``````

For that range, we get a list of all the pairs of values with `.combinations()...`

``````     .combinations(2)
``````

We `.grep()` through that list to find all the pairs where their `.sum()` is evenly divisible by `\$k...`

``````    .grep({ @\$_.sum %% \$k})
``````

…Then we count how many pairs we found… `.elems`

…and print that out.

``````    .say;
``````

(Full code on Github.)

The Perl solution is not quite so concise. For one thing, I had to supply my own `combinations()` function which luckily I had from previous challenges. I also missed having the integer modulus operator `%%` and the `.sum()` method.

``````say scalar grep { (\$list[\$_->] + \$list[\$_->]) % \$k == 0; }
combinations([0 .. scalar @list - 1], 2);
``````

(Full code on Github.)

## Challenge 2: Total Zero

You are given two positive integers `\$x` and `\$y`.

Write a script to find out the number of operations needed to make both `ZERO`. Each operation is made up either of the followings:

``````\$x = \$x - \$y if \$x >= \$y

or

\$y = \$y - \$x if \$y >= \$x (using the original value of \$x)
``````

#### Example 1

``````Input: \$x = 5, \$y = 4
Output: 5
``````

#### Example 2

``````Input: \$x = 4, \$y = 6
Output: 3
``````

#### Example 3

``````Input: \$x = 2, \$y = 5
Output: 4
``````

#### Example 4

``````Input: \$x = 3, \$y = 1
Output: 3
``````

#### Example 5

``````Input: \$x = 7, \$y = 4
Output: 5
``````

Normally function parameters in `Raku` are immutable. To be able to change them, you have to add the `is copy` trait.

``````sub MAIN(
Int \$x is copy, #= a positive integer
Int \$y is copy  #= a positive integer
) {
``````

I defined a counter for the number of operations.

``````    my \$operations = 0;
``````

Then I kept on applying the operations given in the spec until both `\$x` and `\$y` were `0`.

``````    repeat {
``````

In order to perform `operation 2` correctly, I had to `cache` the value of `\$x` before `operation 1` was applied.

``````        my \$prevX = \$x;

if \$x >= \$y {
\$x -= \$y;
}

if \$y >= \$prevX {
\$y -= \$prevX;
}
``````

The spec is misleading IMHO. Originally, I incremented `\$operations` within each `if` block. But for the example inputs, this gave me a result 1 greater than the expected output. What we really want is not the total number of operations as I assumed, but the number of times we go through the loop.

``````        \$operations++;

} until \$x == 0 && \$y == 0;
``````

Finally, we can print the result.

``````    say \$operations;
}
``````

(Full code on Github.)

This is the `Perl` version. No concerns about immutablity and we use `do ... while` instead of `repeat ... until` in the loop.

``````my (\$x, \$y) = @ARGV;
my \$operations = 0;

do {
my \$prevX = \$x;

if (\$x >= \$y) {
\$x -= \$y;
}

if (\$y >= \$prevX) {
\$y -= \$prevX;
}

\$operations++;

} while (\$x != 0 && \$y != 0);

say \$operations;
``````

(Full code on Github.)

If you have any suggestion then please do share with us perlweeklychallenge@yahoo.com.

## SO WHAT DO YOU THINK ?

If you have any suggestions or ideas then please do share with us.