site.base_url }}/">The Bear's Den -->

The Bear's Den

Enter at your own risk

On the Goat Route

Task 1: Goat Latin

Submitted by: Mohammad Sajid Anwar


You are given a sentence, $sentance.

Write a script to convert the given sentence to Goat Latin, a made up language similar to Pig Latin.

Rules for Goat Latin:

1) If a word begins with a vowel ("a", "e", "i", "o", "u"), append
   "ma" to the end of the word.
2) If a word begins with consonant i.e. not a vowel, remove first
   letter and append it to the end then add "ma".
3) Add letter "a" to the end of first word in the sentence, "aa" to
   the second word, etc etc.

Example 1

Input: $sentence = "I love Perl"
Output: "Imaa ovelmaaa erlPmaaaa"

Example 2

Input: $sentence = "Perl and Raku are friends"
Output: "erlPmaa andmaaa akuRmaaaa aremaaaaa riendsfmaaaaaa"

Example 3

Input: $sentence = "The Weekly Challenge"
Output: "heTmaa eeklyWmaaa hallengeCmaaaa"

Solution

This task can be solved using a single substitute operation. We skip space characters, capture an optional single consonant and the following word characters. Reassemble the word and append the suffix in increasing length.

use strict;
use warnings;

sub goat_latin {
    my $na = 1;
    no warnings 'uninitialized';
    shift =~ s#\s*\K(?i:([^aeiou])?)(\w+)#"$2$1m" . ("a" x ++$na)#ger
}

See the full solution to task 1.

Task 2: Bus Route

Submitted by: Peter Campbell Smith


Several bus routes start from a bus stop near my home, and go to the same stop in town. They each run to a set timetable, but they take different times to get into town.

Write a script to find the times - if any - I should let one bus leave and catch a strictly later one in order to get into town strictly sooner.

An input timetable consists of the service interval, the offset within the hour, and the duration of the trip.

Example 1

Input: [ [12, 11, 41], [15, 5, 35] ]
Output: [36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47]

Route 1 leaves every 12 minutes, starting at 11 minutes past the hour (so 11, 23, ...) and takes 41 minutes. Route 2 leaves every 15 minutes, starting at 5 minutes past (5, 20, ...) and takes 35 minutes.

At 45 minutes past the hour I could take the route 1 bus at 47 past the hour, arriving at 28 minutes past the following hour, but if I wait for the route 2 bus at 50 past I will get to town sooner, at 25 minutes past the next hour.

Example 2

Input: [ [12, 3, 41], [15, 9, 35], [30, 5, 25] ]
Output: [ 0, 1, 2, 3, 25, 26, 27, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 55, 56, 57, 58, 59 ]

Solution

This solution isn’t much more than a draft. It will certainly fail in some cases. Sadly, I don’t have enough time this week for a better designed solution. The case where two buses arrive at the same time has not been considered.

To solve this task, we first transform the time table schedules into pairs of departure and arrival times. Then we sort these pairs by arrival and replace the arrival time with a sequence number. This new list is sorted by departure and is the basis for the further process.

We build a hash with the sequence numbers as keys where the smallest number represents the sequence number with the earliest arrival.

Looping over the list created in the first step, we know we shall let the next bus leave if its sequence number is larger than expected. In this case we add the minutes after the previous departure until the current departure to the result. In any case, the observed sequence number is taken off the hash of expected sequence numbers.

use strict;
use warnings;
use feature 'postderef';
use List::Gather;
use List::Util 'min';

sub s2t ($s) {
    map {my $d = $s->[0] * $_ + $s->[1]; [$d, $d + $s->[2]]} 0 .. 60 / $s->[0];
}

sub let_leave {
    my $seq = 0;
    my @tt = sort {$a->[0] <=> $b->[0]}
        map [$_->[0], $seq++],
        sort {$a->[1] <=> $b->[1]}
        map s2t($_), @_;

    gather {
        (\my %expected)->@{0 .. $#tt} = ();
        my $depart = -1;
        for my $next (@tt) {
            my $d = $next->[0];
            my $seq = $next->[1];
            take $depart + 1 .. min $d, 59 if $seq > min keys %expected;
            delete $expected{$seq};
            $depart = $d;
            last if $depart > 59;
        }
    }
}

See the full solution to task 2.


If you have a question about this post or if you like to comment on it, feel free to open an issue in my github repository.