# PERL WEEKLY CHALLENGE – 039

This is my ninth week participating into the weekly challenge.

## Easy Challenge

A guest house had a policy that the light remain ON as long as the at least one guest is in the house. There is guest book which tracks all guest in/out time. Write a script to find out how long in minutes the light were ON.

```1) Alex    IN: 09:10 OUT: 09:45
2) Arnold  IN: 09:15 OUT: 09:33
3) Bob     IN: 09:22 OUT: 09:55
4) Charlie IN: 09:25 OUT: 10:05
5) Steve   IN: 09:33 OUT: 10:01
6) Roger   IN: 09:44 OUT: 10:12
7) David   IN: 09:57 OUT: 10:23
8) Neil    IN: 10:01 OUT: 10:19
9) Chris   IN: 10:10 OUT: 11:00
```

I solved this by converting the hh::mm timestamp into absolute minutes and iterating through each minute that the light is on and storing that into a hash. The hash is sampled per minute and the last minute isn’t sampled.

For example: 10:10 – 10:11 will only store the absolute minute 610 into the hash and not 610 and 611.

In Raku, I pretty much did the same thing.

#### Perl 5 solution

``````#!/usr/bin/perl
# Test: ./ch1.pl
use strict;
use warnings;
use feature qw /say/;

my \$minutes_on = calculate_lights_on();

say 'Lights on for: ' .
\$minutes_on . ' minutes';

# Calculate the minutes lights were on
sub calculate_lights_on {
my %time_on; # Sample in minutes
my \$time_re = qr/\d{2}\:\d{2}/;

while (my \$line = <DATA>) {
next unless \$line =~
/.*?(\$time_re).*?(\$time_re)/;

# Get the time in absolute minutes
my \$t1 = absolute_minutes(\$1);
my \$t2 = absolute_minutes(\$2);

# Populate the time on hash
for my \$minute (\$t1 .. (\$t2 - 1)) {
\$time_on{\$minute} = 1;
}
}

return scalar(keys %time_on);
}

# Convert to absolute mins.
sub absolute_minutes {
my (\$hh, \$mm) = split(':', shift);
return \$hh * 60 + \$mm;
}

__DATA__
1) Alex    IN: 09:10 OUT: 09:45
2) Arnold  IN: 09:15 OUT: 09:33
3) Bob     IN: 09:22 OUT: 09:55
4) Charlie IN: 09:25 OUT: 10:05
5) Steve   IN: 09:33 OUT: 10:01
6) Roger   IN: 09:44 OUT: 10:12
7) David   IN: 09:57 OUT: 10:23
8) Neil    IN: 10:01 OUT: 10:19
9) Chris   IN: 10:10 OUT: 11:00
``````

Output

``Lights on for: 110 minutes``

#### Raku solution

``````# Test: perl6 ch1.p6
use v6.d;

sub MAIN() {
my \$minutes_on = calculate-lights-on();

say 'Lights on for: ' ~
\$minutes_on ~
' minutes';
}

# Calculate the minutes lights were on
sub calculate-lights-on {
my %time_on; # Sample in minutes
my \$time_re = /\d\d\:\d\d/;

for data().lines -> \$line {
next unless \$line ~~
/.*?(\$time_re).*?(\$time_re)/;

# Get the time in absolute minutes
my \$t1 = absolute-minutes(\$0);
my \$t2 = absolute-minutes(\$1);

%time_on{\$t1 .. (\$t2 -1)} = 1;
}

return %time_on.elems;
}

# Convert to absolute mins.
sub absolute-minutes(\$hh_mm) {
my (\$hh, \$mm) = \$hh_mm.split(':');
return \$hh * 60 + \$mm;
}

# The data
sub data {
return q:to/END/;
1) Alex    IN: 09:10 OUT: 09:45
2) Arnold  IN: 09:15 OUT: 09:33
3) Bob     IN: 09:22 OUT: 09:55
4) Charlie IN: 09:25 OUT: 10:05
5) Steve   IN: 09:33 OUT: 10:01
6) Roger   IN: 09:44 OUT: 10:12
7) David   IN: 09:57 OUT: 10:23
8) Neil    IN: 10:01 OUT: 10:19
9) Chris   IN: 10:10 OUT: 11:00
END
}
``````

Output

``Lights on for: 110 minutes``

## Hard Challenge

Write a script to demonstrate Reverse Polish notation(RPN). Checkout the wiki page for more information about RPN.

For this challenge I just followed the algorithm shown below. I used a dispatch table for the operations and made it a bit more utf-8 friendly.

```for each token in the postfix expression:
if token is an operator:
operand_2 ← pop from the stack
operand_1 ← pop from the stack
result ← evaluate token with operand_1 and operand_2
push result back onto the stack
else if token is an operand:
push token onto the stack
result ← pop from the stack```

#### Perl 5 solution

``````#!/usr/bin/perl
# test: ./ch2.pl "15 7 1 1 + − ÷ 3 × 2 1 1 + + −"
use strict;
use warnings;
use feature qw /say/;

say evaluate_stack(\$ARGV);

# Evaluate the stack
sub evaluate_stack {
my @tokens = split(/\s/, shift);
my @stack;

# Some utf-8 friendly operations
my \$operations = {
'-' => \&subtract,
'−' => \&subtract,
'*' => \&multiply,
'×' => \&multiply,
'÷' => \&divide,
'/' => \&divide,
};

for my \$token (@tokens) {
if (\$operations->{\$token}) {
push @stack, \$operations->{\$token}->(\@stack);
} elsif (\$token =~ /\d+/) {
push @stack, \$token;
}
}

return pop(@stack);
}

# Operations
sub add      { my \$s = shift; return pop(@\$s) + pop(@\$s) }
sub subtract { my \$s = shift; return - pop(@\$s) + pop(@\$s) }
sub multiply { my \$s = shift; return pop(@\$s) * pop(@\$s) }
sub divide   { my \$s = shift; return (1 / pop(@\$s)) * pop(@\$s) }
``````

Test like this
./ch2.pl “15 7 1 1 + − ÷ 3 × 2 1 1 + + −”

Output
5

#### Raku solution

``````# Test: perl6 ./ch2.p6 "15 7 1 1 + − ÷ 3 × 2 1 1 + + −"
use v6.d;

sub MAIN (Str \$tokens) {
say evaluate-stack(\$tokens.split(/\s/));
}

# Evaluate the stack
sub evaluate-stack(@tokens) {
my @stack;

# Some utf-8 friendly operations
my %operations = (
'-' => &subtract,
'−' => &subtract,
'*' => &multiply,
'×' => &multiply,
'÷' => &divide,
'/' => &divide,
);

# Process each token
for (@tokens) -> \$token {
if (%operations.{\$token}) {
push @stack, %operations.{\$token}(@stack);
} elsif (\$token ~~ /\d+/) {
push @stack, \$token;
}
}

return pop(@stack);
}

# Operations
sub add(@s)      { return @s.pop + @s.pop }
sub subtract(@s) { return - @s.pop + @s.pop }
sub multiply(@s) { return @s.pop * @s.pop }
sub divide(@s)   { return (1 / @s.pop) * @s.pop }
``````

Test like this
perl6 ./ch2.p6 “15 7 1 1 + − ÷ 3 × 2 1 1 + + −”

Output
5