aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorUtil <bruce.gray@acm.org>2022-10-23 16:00:18 -0500
committerUtil <bruce.gray@acm.org>2022-10-23 16:00:18 -0500
commit9b716d57b0ebfc7454b5868c1d90f47bc07c0bf4 (patch)
tree3e8703af4b535aa397ac96b24c046245f595101d
parentf379ea9eabcb675797f124f29bacd787bb04b610 (diff)
downloadperlweeklychallenge-club-9b716d57b0ebfc7454b5868c1d90f47bc07c0bf4.tar.gz
perlweeklychallenge-club-9b716d57b0ebfc7454b5868c1d90f47bc07c0bf4.tar.bz2
perlweeklychallenge-club-9b716d57b0ebfc7454b5868c1d90f47bc07c0bf4.zip
Add TWC 187 solutions by Bruce Gray : Raku only.
-rw-r--r--challenge-187/bruce-gray/raku/ch-1.raku96
-rw-r--r--challenge-187/bruce-gray/raku/ch-2.raku71
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;
+}