diff options
| -rw-r--r-- | challenge-187/bruce-gray/raku/ch-1.raku | 96 | ||||
| -rw-r--r-- | challenge-187/bruce-gray/raku/ch-2.raku | 71 |
2 files changed, 167 insertions, 0 deletions
diff --git a/challenge-187/bruce-gray/raku/ch-1.raku b/challenge-187/bruce-gray/raku/ch-1.raku new file mode 100644 index 0000000000..3d3411f325 --- /dev/null +++ b/challenge-187/bruce-gray/raku/ch-1.raku @@ -0,0 +1,96 @@ + +# Not needed (could use Set), but more efficient this way, and these lines are reusable +multi sub infix:<∩> ( Range \a, Range \b --> Range ) { (a,b)».min.max .. (a,b)».max.min } +multi sub infix:<∪> ( Range \a, Range \b --> Range ) { (a,b)».min.min .. (a,b)».max.max } + +sub task1 ( @itineraries ) { + sub offset ( Str $s --> Date ) { + $s ~~ / ^ (\d\d) '-' (\d\d) $ / + orelse die; + + return Date.new(2001, +$1, +$0) + } + + my Range @z = @itineraries.map: -> ($s, $e) { + Range.new( |map &offset, ($s, $e) ); + } + + return elems [∩] @z; +} + +sub get_tests ( ) { + my $test_data = q:to/END/; + Example 1 + + Input: Foo => SD: '12-01' ED: '20-01' + Bar => SD: '15-01' ED: '18-01' + + Output: 4 days + + Example 2 + + Input: Foo => SD: '02-03' ED: '12-03' + Bar => SD: '13-03' ED: '14-03' + + Output: 0 day + + Example 3 + + Input: Foo => SD: '02-03' ED: '12-03' + Bar => SD: '11-03' ED: '15-03' + + Output: 2 days + + Example 4 + + Input: Foo => SD: '30-03' ED: '05-04' + Bar => SD: '28-03' ED: '02-04' + + Output: 4 days + + + Extra 1 + + Input: Foo => SD: '30-03' ED: '05-04' + + Output: 7 days + + Extra 2 + + Input: Foo => SD: '30-03' ED: '05-04' + Bar => SD: '28-03' ED: '02-04' + Baz => SD: '01-04' ED: '02-04' + + Output: 2 days + + END + my regex dashedDate { \d\d \- \d\d } + my regex input { \w+ \s* '=>' \s* 'SD:' \s* \'(<dashedDate>)\' + \s* 'ED:' \s* \'(<dashedDate>)\' } + my $re = / + \s* $<name>=[[Example|Extra] \s+ \d+] + \s* 'Input:' \s* <input>+ % \s+ + \s* 'Output:' \s* $<expected>=[\d+] \s* days? + /; + + my @tests = $test_data.match(:g, $re); + + my @r; + for @tests -> Match $test { + my @starts_and_ends = gather for $test.<input>.list -> Match $i { + take $i.map(~*.<dashedDate>).cache; + } + push @r, { + name => "$test.<name>: @starts_and_ends[]", + expected => +$test.<expected>, + in => @starts_and_ends, + }; + } + return @r; +} +use Test; +my @tests = get_tests(); +plan +@tests; +for @tests -> %t { + is task1(%t<in>), %t<expected>, %t<name>; +} diff --git a/challenge-187/bruce-gray/raku/ch-2.raku b/challenge-187/bruce-gray/raku/ch-2.raku new file mode 100644 index 0000000000..079da40048 --- /dev/null +++ b/challenge-187/bruce-gray/raku/ch-2.raku @@ -0,0 +1,71 @@ +# Simple, but two passes: +# sub max_list ( @a, &c ) { +# my $max = @a.map(&c).max; +# return @a.grep( *.&c == $max ); +# } + +# Single-pass: +sub max_list ( Iterable $a, Code $c ) { + my ( $max, @r ); + for $a.list -> $aa { + my $cc = $aa.$c; + $max //= $cc; + given $cc cmp $max { + when Order::More { @r = $aa; $max = $cc; } + when Order::Same { @r.push: $aa; } + when Order::Less {} # Do nothing + } + } + return @r; +} + +# Concise, but not better eough to get away from the literal task definition. +# sub valid_triangle_sides ( @abc where *.elems == 3 --> Bool ) { +# return @abc.permutations.map(-> (\a, \b, \c) { a + b > c }).all.so; +# return @abc.permutations.map({ .[0,1].sum > .[2] }).all.so; +# } + +sub valid_triangle_sides ( (\a, \b, \c) --> Bool ) { + return a + b > c + && b + c > a + && a + c > b; +} +sub task2 ( @a ) { + # XXX .combinations does not allow for early exit on $c! So, non-optimal. + my @r = @a.sort(-*).combinations(3).grep(&valid_triangle_sides); + + return @r.&max_list({ .sum }).first({ [≥] .list }) // (); +} + + +constant @fibonacci = ( 1, 1, * + * ... * ).head(50); +constant @powers_of_2 = ( 1, * * 2 ... * ).head(50); +constant @powers_of_2_4 = 1, 4, 4, |@powers_of_2.skip(3); +constant @powers_of_2_1 = @powers_of_2.skip(1) X- 1; + +# From: raku -e 'my @a = (1..^10_000).roll(100); say @a.join(",")' +constant @random_100 = 8188,203,44,2634,2658,603,6912,6292,1518,1047,2341,9358,1238,2154,8715,8558,8550,7253,2547,8800,780,4020,2352,5863,6057,7497,8296,6641,8653,3654,5314,9072,8029,6522,8388,8789,9762,4265,79,7714,9014,8671,3385,9961,4078,6256,6311,5816,1790,1396,8631,7488,4469,9897,1419,6340,957,7876,3604,3218,5495,9876,5696,3233,1635,9845,7164,6546,228,3824,2862,8065,8251,9521,5043,7813,2189,6273,7870,7947,2526,5706,6751,4350,1199,8915,9397,4398,9245,3916,7977,2749,3944,8073,3410,1617,9150,7324,8374,4776; + + +my @tests = + # Original examples from TWC 187: + ( :Ex1(1, 2, 3, 2) , (3, 2, 2) ), + ( :Ex2(1, 3, 2) , () ), + ( :Ex3(1, 1, 2, 3) , () ), + ( :Ex4(2, 4, 3) , (4, 3, 2) ), + + # Extra tests, by author: + ( :Short(2, 4) , () ), + ( :@powers_of_2 , () ), + ( :@powers_of_2_4 , (4, 4, 1) ), + ( :@powers_of_2_1 , () ), + ( :@fibonacci , () ), + ( :@random_100, @random_100.sort(-*).head(3) ), + +; +use Test; +plan +@tests; +for @tests { + my ( $name, $input, $expected ) = .[0].key, .[0].value, .[1]; + is-deeply task2($input), $expected, $name; +} |
