Weekly Challenge #080 Task #2 :: Raku
Tags: raku, perlweeklychallenge, perl, challenge
Published: 2020-09-30 01:08:49

# [Task #2](https://perlweeklychallenge.org/blog/perl-weekly-challenge-080/#TASK2) Count Candies
Submitted by: Mohammad S Anwar

You are given rankings of @N candidates.

Write a script to find out the total candies needed for all
candidates. You are asked to follow the rules below:
a) You must given at least one candy to each candidate.
b) Candidate with higher ranking get more candies than their mediate neighbors on either side.
## Example 1:
```
Input: @N = (1, 2, 2)
```
##Explanation:
```
Applying rule #a, each candidate will get one candy. 
So total candies needed so far 3.
 Now applying rule #b,  the first candidate do not get any more
candy as its rank is lower than it's neighbours.
  The second candidate gets one more candy as it's ranking is
higher than it's neighbour.
  Finally the third candidate do not get any extra candy
as it's ranking is not higher than neighbour.
  Therefore total candies required is 4.

Output: 4
```

# Example 2:
```
Input: @N = (1, 4, 3, 2)
```
```
Applying rule #a, each candidate will get one candy. So total candies needed so far 4.
  Now applying rule #b, the first candidate do not get any more candy as its rank is lower than it's neighbours.
The second candidate gets two more candies as it's ranking is
higher than it's both neighbour. The third candidate gets
one more candy as it's ranking is higher than it's neighbour.
  Finally the fourth candidate do not get any extra candy
as it's ranking is not higher than neighbour.
  Therefore total candies required is 7.

Output: 7
```

 At first, if you don't the look at the explanation, it is easy to think they are seating in a circular group. I hope it would be more interesting if they are seating along with each other and looking at the candies in front of them. :-]

So I took another journey with [Raku](https://www.raku.org)
If we are getting only one candy and get hungry
the solution might look like ...
```perl
sub candies( *@nums where @nums.all ~~ UInt ) {
    @nums.elems.say;
}
```
```perl
> candies(1, 4, 3, 2);
4
```

but we are human.. getting more, if we have higher ranking.
to look at the neighbour's ranking, I used [rotor](https://docs.raku.org/routine/rotor) again.
but each first and last element has only one neighbour.
It will be probably handy if we add android neighbour next to them.
I used "Inf" in this case, so the android will never give you an extra candy.

```perl
sub MAIN( *@nums where @nums.all ~~ UInt ) {
    (Inf, |@nums, Inf).
    rotor(3=>-1).
    say;
}
```

```sh
raku test.raku 1 4 3 2 # example #2
((Inf 1 4) (1 4 3) (4 3 2) (3 2 Inf))
```

so we can now see how we could can one or two more candies when compared to neighbours (even if we are at one hundred higher position to them so people get lazy)

```perl
sub MAIN( *@nums where @nums.all ~~ UInt ) {
    (Inf,|@nums,Inf).
    rotor(3=>-2).
    kv. # takes each elements as key => value
    map( -> $index, $grp {
              my $c = 1; # rule "a"
              if $grp[0] < $grp[1] {
                  ++$c;
              }
              if $grp[2] < $grp[1] {
                  ++$c;
              }
              "{$index} gets => $c as {$grp}"
           } ).
    join("\n").
    say;
}
```

```sh
0 gets => 1 as Inf 1 4
1 gets => 3 as 1 4 3
2 gets => 2 as 4 3 2
3 gets => 1 as 3 2 Inf
```

I believe that it is always good habit to check the given data and result is matched what I intend to get.
and we now we can add them all into one summation form.

but if we think it is a correct method. why not make it shorter?
so I tried to get a little compact(golfed) code.

and final form is ...
```perl
sub MAIN{(|@_,|((|@_,|@_.reverse).rotor(2=>-1).map({[-] $_}).grep(*>0))).elems.say}
```

as I mentioned before. I'm not a type of golf programmer.
and there is - surprisingly - always... a shorter way to do the task.