diff options
| -rw-r--r-- | challenge-274/athanasius/perl/ch-1.pl | 195 | ||||
| -rw-r--r-- | challenge-274/athanasius/perl/ch-2.pl | 302 | ||||
| -rw-r--r-- | challenge-274/athanasius/raku/ch-1.raku | 191 | ||||
| -rw-r--r-- | challenge-274/athanasius/raku/ch-2.raku | 314 |
4 files changed, 1002 insertions, 0 deletions
diff --git a/challenge-274/athanasius/perl/ch-1.pl b/challenge-274/athanasius/perl/ch-1.pl new file mode 100644 index 0000000000..b0e03ee9ec --- /dev/null +++ b/challenge-274/athanasius/perl/ch-1.pl @@ -0,0 +1,195 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 274 +========================= + +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" + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Assumption +---------- +Within a series of "word" (alphabetic) characters, a hyphen is taken to be a +separator of distinct words. + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. The input sentence is entered as an unnamed (positional) argument on the + command-line. + +=cut +#=============================================================================== + +use v5.32.1; # Enables strictures +use warnings; +use Const::Fast; +use Test::More; + +const my $USAGE => <<END; +Usage: + perl $0 <sentence> + perl $0 + + <sentence> A sentence to be translated into Goat Latin +END + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 274, Task #1: Goat Latin (Perl)\n\n"; +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + my $argc = scalar @ARGV; + + if ($argc == 0) + { + run_tests(); + } + elsif ($argc == 1) + { + my $sentence = $ARGV[ 0 ]; + + print qq[Input: \$sentence = "$sentence"\n]; + + my $translation = translate( $sentence ); + + print qq[Output: "$translation"\n]; + } + else + { + error( "Expected 1 or 0 command-line arguments, found $argc" ); + } +} + +#------------------------------------------------------------------------------- +sub translate +#------------------------------------------------------------------------------- +{ + my ($sentence) = @_; + my $translation = ''; + my $count = 1; + + for my $chunk (split / \b /x, $sentence) # Split on word boundaries + { + if ($chunk =~ / \w /x) # (1) The chunk is a word that... + { + if ($chunk =~ / ^ [aeiou] /ix) # (1a) ...begins with a vowel + { + $translation .= $chunk; + } + else # (1b) ...begins with a consonant + { + $translation .= substr( $chunk, 1 ) . substr( $chunk, 0, 1 ); + } + + $translation .= 'ma' . 'a' x $count++; # Append goatish suffix + } + else # (2) The chunk is space(s) and/or punctuation + { + $translation .= $chunk; + } + } + + return $translation; +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + while ($line =~ / \\ $ /x) + { + chop $line; + + $line .= <DATA> =~ s/ ^ \s+ //rx; + } + + my ($test_name, $sentence, $expected) = split / \| /x, $line; + + for ($test_name, $sentence, $expected) + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my $translation = translate( $sentence ); + + is $translation, $expected, $test_name; + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 1|I love Perl |Imaa ovelmaaa erlPmaaaa +Example 2|Perl and Raku are friends|erlPmaa andmaaa akuRmaaaa aremaaaaa \ + riendsfmaaaaaa +Example 3|The Weekly Challenge |heTmaa eeklyWmaaa hallengeCmaaaa diff --git a/challenge-274/athanasius/perl/ch-2.pl b/challenge-274/athanasius/perl/ch-2.pl new file mode 100644 index 0000000000..0d32dff1b7 --- /dev/null +++ b/challenge-274/athanasius/perl/ch-2.pl @@ -0,0 +1,302 @@ +#!perl + +################################################################################ +=comment + +Perl Weekly Challenge 274 +========================= + +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 ] + +=cut +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. One or more "timetable strings" are entered as unnamed arguments on the + command-line. Each timetable string contains a service-interval, an hour- + offset, and a trip-duration, separated by whitespace (with optional commas). + +=cut +#=============================================================================== + +use v5.32.1; # Enables strictures +use warnings; +use Const::Fast; +use Test::More; + +const my $USAGE => <<END; +Usage: + perl $0 [<timetables> ...] + perl $0 + + [<timetables> ...] Timetable-strings, e.g., "12 11 41" "15 5 35" +END + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + $| = 1; + print "\nChallenge 274, Task #2: Bus Route (Perl)\n\n"; +} + +#------------------------------------------------------------------------------- +package Route +#------------------------------------------------------------------------------- +{ + use Class::Accessor 'antlers'; + + has interval => ( is => 'ro', isa => 'Num' ); + has offset => ( is => 'ro', isa => 'Num' ); + has duration => ( is => 'ro', isa => 'Num' ); + + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + sub next_start + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + my ($self, $current_time) = @_; + + my $time = $self->offset; + $time += $self->interval while $time < $current_time; + + return $time; + } + + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + sub next_arrival + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + my ($self, $leave_time) = @_; + + return $leave_time + $self->duration; + } +} + +#=============================================================================== +MAIN: +#=============================================================================== +{ + if (scalar @ARGV == 0) + { + run_tests(); + } + else + { + my $routes = parse_timetables( \@ARGV ); + + printf "Input: [ %s ]\n", join ', ', map { sprintf '[%d, %d, %d]', + $_->interval, $_->offset, $_->duration } @$routes; + + my $leave_times = find_leave_times( $routes ); + + printf "Output: [ %s ]\n", join ', ', @$leave_times; + } +} + +#------------------------------------------------------------------------------- +sub find_leave_times +#------------------------------------------------------------------------------- +{ + my ($routes) = @_; + my @leave_times; + + for my $current_time (0 .. 59) + { + my ($min_route, $min_start, $min_arrival) = + find_min_start( $routes, $current_time ); + + for my $i (0 .. $#$routes) + { + next if $i == $min_route; + + my $start = $routes->[ $i ]->next_start( $current_time ); + + if ($start > $min_start) + { + my $arrival = $routes->[ $i ]->next_arrival( $start ); + + if ($arrival < $min_arrival) + { + push @leave_times, $current_time; + last; + } + } + } + } + + return \@leave_times; +} + +#------------------------------------------------------------------------------- +sub find_min_start +#------------------------------------------------------------------------------- +{ + my ($routes, $current_time) = @_; + + my $min_route = 0; + my $min_start = $routes->[ 0 ]->next_start( $current_time ); + my $min_arrival = $routes->[ 0 ]->next_arrival( $min_start ); + + for my $i (1 .. $#$routes) + { + my $start_time = $routes->[ $i ]->next_start( $current_time ); + + if ($start_time < $min_start) + { + $min_route = $i; + $min_start = $start_time; + $min_arrival = $routes->[ $i ]->next_arrival( $min_start ); + } + elsif ($start_time == $min_start) + { + my $arrival = $routes->[ $i ]->next_arrival( $min_start ); + + if ($arrival < $min_arrival) + { + $min_route = $i; + $min_start = $start_time; + $min_arrival = $arrival; + } + } + } + + return ($min_route, $min_start, $min_arrival); +} + +#------------------------------------------------------------------------------- +sub parse_timetables +#------------------------------------------------------------------------------- +{ + my ($timetables) = @_; + my @routes; + + for my $timetable (@$timetables) + { + $timetable =~ / ^ \s* (\d+) \,? \s+ (\d+) \,? \s+ (\d+) \s* $ /x + or error( qq[Invalid input timetable "$timetable"] ); + + my ($interval, $offset, $duration) = @{ ^CAPTURE }; + + 0 < $interval or error( qq["$interval" is not a valid interval] ); + 0 <= $offset < 60 or error( qq["$offset" is not a valid offset] ); + + push @routes, Route->new( { interval => $interval, + offset => $offset, + duration => $duration } ); + } + + return \@routes; +} + +#------------------------------------------------------------------------------- +sub run_tests +#------------------------------------------------------------------------------- +{ + print "Running the test suite\n"; + + while (my $line = <DATA>) + { + chomp $line; + + my ($test_name, $timetables_str, $expected_str) = split / \| /x, $line; + + for ($test_name, $timetables_str, $expected_str) + { + s/ ^ \s+ //x; + s/ \s+ $ //x; + } + + my @timetables = split / \; \s+ /x, $timetables_str; + my $routes = parse_timetables( \@timetables ); + my $leave_times = find_leave_times( $routes ); + my $expected = parse_expected( $expected_str ); + + is_deeply $leave_times, $expected, $test_name; + } + + done_testing; +} + +#------------------------------------------------------------------------------- +sub parse_expected +#------------------------------------------------------------------------------- +{ + my ($expected_str) = @_; + my @expected; + + for my $s (split / \s+ /x, $expected_str) + { + if ($s =~ / ^ (\d+) \- (\d+) $ /x) + { + push @expected, $1 .. $2; + } + else + { + push @expected, $s; + } + } + + return \@expected; +} + +#------------------------------------------------------------------------------- +sub error +#------------------------------------------------------------------------------- +{ + my ($message) = @_; + + die "ERROR: $message\n$USAGE"; +} + +################################################################################ + +__DATA__ +Example 1 |12 11 41; 15 5 35 |36-47 +Example 2 |12 3 41; 15 9 35; 30 5 25 |0-3 25-27 40-51 55-59 +One route 1|12 3 41 | +One route 2|12 3 41; 12 3 41 | +Longer |12 3 42; 12 3 41 | +Example 1a |12 11 41; 15 5 35; 15 5 36 |36-47 +Example 2a |12 3 41; 15 9 35; 30 5 25; 15 9 36|0-3 25-27 40-51 55-59 diff --git a/challenge-274/athanasius/raku/ch-1.raku b/challenge-274/athanasius/raku/ch-1.raku new file mode 100644 index 0000000000..9f49ee669d --- /dev/null +++ b/challenge-274/athanasius/raku/ch-1.raku @@ -0,0 +1,191 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 274 +========================= + +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" + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Assumption +---------- +Within a series of "word" (alphabetic) characters, a hyphen is taken to be a +separator of distinct words. + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. The input sentence is entered as an unnamed (positional) argument on the + command-line. + +=end comment +#=============================================================================== + +use Test; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 274, Task #1: Goat Latin (Raku)\n".put; +} + +#=============================================================================== +multi sub MAIN +( + Str:D $sentence #= A sentence to be translated into Goat Latin +) +#=============================================================================== +{ + qq[Input: \$sentence = "$sentence"].put; + + my Str $translation = translate( $sentence ); + + qq[Output: "$translation"].put; +} + +#=============================================================================== +multi sub MAIN() # No input: run the test suite +#=============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------- +sub translate( Str:D $sentence --> Str:D ) +#------------------------------------------------------------------------------- +{ + my Str $translation = ''; + my UInt $count = 1; + + for $sentence.split: / <|w> /, :skip-empty -> Str $chunk # Split on word + { # boundaries + if $chunk ~~ / \w / # (1) The chunk is a word that... + { + if $chunk ~~ m:i/ ^ <[aeiou]> / # (1a) ...begins with a vowel + { + $translation ~= $chunk; + } + else # (1b) ...begins with a consonant + { + $translation ~= $chunk.substr( 1 ) ~ $chunk.substr( 0, 1 ); + } + + $translation ~= 'ma' ~ 'a' x $count++; # Append goatish suffix + } + else # (2) The chunk is space(s) and/or punctuation + { + $translation ~= $chunk; + } + } + + return $translation; +} + +#------------------------------------------------------------------------------- +sub run-tests() +#------------------------------------------------------------------------------- +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $sentence, $expected) = $line.split: / \| /; + + for $test-name, $sentence, $expected + { + s/ ^ \s+ //; + s/ \s+ $ //; + } + + my Str $translation = translate( $sentence ); + + is $translation, $expected, $test-name; + } + + done-testing; +} + +#------------------------------------------------------------------------------- +sub error( Str:D $message ) +#------------------------------------------------------------------------------- +{ + "ERROR: $message".put; + + USAGE(); + + exit 0; +} + +#------------------------------------------------------------------------------- +sub USAGE() +#------------------------------------------------------------------------------- +{ + my Str $usage = $*USAGE; + + $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +#------------------------------------------------------------------------------- +sub test-data( --> Str:D ) +#------------------------------------------------------------------------------- +{ + my Str $data = q:to/END/; + Example 1|I love Perl |Imaa ovelmaaa erlPmaaaa + Example 2|Perl and Raku are friends|erlPmaa andmaaa akuRmaaaa aremaaaaa\ + riendsfmaaaaaa + Example 3|The Weekly Challenge |heTmaa eeklyWmaaa hallengeCmaaaa + END + + $data ~~ s:g/ \\ \n //; # Concatenate backslashed lines + + return $data; +} + +################################################################################ diff --git a/challenge-274/athanasius/raku/ch-2.raku b/challenge-274/athanasius/raku/ch-2.raku new file mode 100644 index 0000000000..0e4bd64879 --- /dev/null +++ b/challenge-274/athanasius/raku/ch-2.raku @@ -0,0 +1,314 @@ +use v6d; + +################################################################################ +=begin comment + +Perl Weekly Challenge 274 +========================= + +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 ] + +=end comment +################################################################################ + +#--------------------------------------# +# Copyright © 2024 PerlMonk Athanasius # +#--------------------------------------# + +#=============================================================================== +=begin comment + +Interface +--------- +1. If no command-line arguments are given, the test suite is run. Otherwise: +2. One or more "timetable strings" are entered as unnamed arguments on the + command-line. Each timetable string contains a service-interval, an hour- + offset, and a trip-duration, separated by whitespace (with optional commas). + +=end comment +#=============================================================================== + +use Test; + +subset Interval of Int where 0 < *; +subset Offset of Int where 0 <= * < 60; + +#------------------------------------------------------------------------------- +BEGIN +#------------------------------------------------------------------------------- +{ + "\nChallenge 274, Task #2: Bus Route (Raku)\n".put; +} + +#------------------------------------------------------------------------------- +class Route +#------------------------------------------------------------------------------- +{ + # All measurements in minutes + has Interval $.interval is required; # Service interval + has Offset $.offset is required; # Offset within the hour + has UInt $.duration is required; # Duration of the trip + + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + method next-start( Offset:D $current-time --> UInt:D ) + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + my UInt $time = $!offset; + $time += $!interval while $time < $current-time; + + return $time; + } + + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + method next-arrival( UInt:D $leave-time --> UInt:D ) + #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + { + return $leave-time + $!duration; + } +} + +#=============================================================================== +multi sub MAIN +( + #| Timetable-strings, e.g., "12 11 41" "15 5 35" + + *@timetables where { .elems > 0 } +) +#=============================================================================== +{ + my Route @routes = parse-timetables( @timetables ); + + "Input: [ %s ]\n".printf: + @routes.map( + { '[%d, %d, %d]'.sprintf: .interval, .offset, .duration } + + ).join: ', '; + + my Offset @leave-times = find-leave-times( @routes ); + + "Output: [ %s ]\n".printf: @leave-times.join: ', '; +} + +#=============================================================================== +multi sub MAIN() # No input: run the test suite +#=============================================================================== +{ + run-tests(); +} + +#------------------------------------------------------------------------------- +sub find-leave-times( List:D[Route:D] $routes --> List:D[Offset:D] ) +#------------------------------------------------------------------------------- +{ + my Offset @leave-times; + + for 0 ..^ 60 -> Offset $current-time + { + my UInt ($min-route, $min-start, $min-arrival) = + find-min-start( $routes, $current-time ); + + for 0 .. $routes.end -> UInt $i + { + next if $i == $min-route; + + my UInt $start = $routes[ $i ].next-start( $current-time ); + + if $start > $min-start + { + my UInt $arrival = $routes[ $i ].next-arrival( $start ); + + if $arrival < $min-arrival + { + @leave-times.push: $current-time; + last; + } + } + } + } + + return @leave-times; +} + +#------------------------------------------------------------------------------- +sub find-min-start +( + List:D[Route:D] $routes, + Offset:D $current-time +--> List:D[UInt:D] +) +#------------------------------------------------------------------------------- +{ + my UInt $min-route = 0; + my UInt $min-start = $routes[ 0 ].next-start( $current-time ); + my UInt $min-arrival = $routes[ 0 ].next-arrival( $min-start ); + + for 1 .. $routes.end -> UInt $i + { + my UInt $start-time = $routes[ $i ].next-start( $current-time ); + + if $start-time < $min-start + { + $min-route = $i; + $min-start = $start-time; + $min-arrival = $routes[ $i ].next-arrival( $min-start ); + } + elsif $start-time == $min-start + { + my UInt $arrival = $routes[ $i ].next-arrival( $min-start ); + + if $arrival < $min-arrival + { + $min-route = $i; + $min-start = $start-time; + $min-arrival = $arrival; + } + } + } + + return $min-route, $min-start, $min-arrival; +} + +#------------------------------------------------------------------------------- +sub parse-timetables( List:D[Str:D] $timetables --> List:D[Route:D] ) +#------------------------------------------------------------------------------- +{ + my Route @routes; + + for @$timetables -> Str $timetable + { + $timetable ~~ / ^ \s* (\d+) \,? \s+ (\d+) \,? \s+ (\d+) \s* $ / + or error( qq[Invalid input timetable "$timetable"] ); + + my Int ($interval, $offset, $duration) = $/.map: { .Int }; + + 0 < $interval or error( qq["$interval" is not a valid interval] ); + 0 <= $offset < 60 or error( qq["$offset" is not a valid offset] ); + + @routes.push: Route.new: :$interval, :$offset, :$duration; + } + + return @routes; +} + +#------------------------------------------------------------------------------- +sub run-tests() +#------------------------------------------------------------------------------- +{ + 'Running the test suite'.put; + + for test-data.lines -> Str $line + { + my Str ($test-name, $timetables-str, $expected-str) = + $line.split: / \| /; + + for $test-name, $timetables-str, $expected-str + { + s/ ^ \s+ //; + s/ \s+ $ //; + } + + my Str @timetables = $timetables-str.split: / \; \s+ /; + my Route @routes = parse-timetables( @timetables ); + my Offset @leave-times = find-leave-times( @routes ); + my Offset @expected = parse-expected( $expected-str ); + + is-deeply @leave-times, @expected, $test-name; + } + + done-testing; +} + +#------------------------------------------------------------------------------- +sub parse-expected( Str:D $expected-str --> List:D[Offset:D] ) +#------------------------------------------------------------------------------- +{ + my Offset @expected; + + for $expected-str.split( / \s+ /, :skip-empty ) -> Str $s + { + if $s ~~ / ^ (\d+) \- (\d+) $ / + { + my UInt ($begin, $end) = $/.map: { .Int }; + + @expected.push: |($begin .. $end); + } + else + { + @expected.push: $s.Int; + } + } + + return @expected; +} + +#------------------------------------------------------------------------------- +sub error( Str:D $message ) +#------------------------------------------------------------------------------- +{ + "ERROR: $message".put; + + USAGE(); + + exit 0; +} + +#------------------------------------------------------------------------------- +sub USAGE() +#------------------------------------------------------------------------------- +{ + my Str $usage = $*USAGE; + + $usage ~~ s:g/ ($*PROGRAM-NAME) /raku $0/; + + $usage.put; +} + +#------------------------------------------------------------------------------- +sub test-data( --> Str:D ) +#------------------------------------------------------------------------------- +{ + return q:to/END/; + Example 1 |12 11 41; 15 5 35 |36-47 + Example 2 |12 3 41; 15 9 35; 30 5 25 |0-3 25-27 40-51 55-59 + One route 1|12 3 41 | + One route 2|12 3 41; 12 3 41 | + Longer |12 3 42; 12 3 41 | + Example 1a |12 11 41; 15 5 35; 15 5 36 |36-47 + Example 2a |12 3 41; 15 9 35; 30 5 25; 15 9 36|0-3 25-27 40-51 55-59 + END +} + +################################################################################ |
