aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--challenge-189/bruce-gray/blog.txt1
-rwxr-xr-xchallenge-189/bruce-gray/perl/ch-1.pl24
-rwxr-xr-xchallenge-189/bruce-gray/perl/ch-2.pl58
-rw-r--r--challenge-189/bruce-gray/raku/ch-1.raku20
-rw-r--r--challenge-189/bruce-gray/raku/ch-2.raku39
5 files changed, 142 insertions, 0 deletions
diff --git a/challenge-189/bruce-gray/blog.txt b/challenge-189/bruce-gray/blog.txt
new file mode 100644
index 0000000000..61dc741db9
--- /dev/null
+++ b/challenge-189/bruce-gray/blog.txt
@@ -0,0 +1 @@
+http://blogs.perl.org/users/bruce_gray/2022/11/twc-189-saving-your-degree-by-great-character.html
diff --git a/challenge-189/bruce-gray/perl/ch-1.pl b/challenge-189/bruce-gray/perl/ch-1.pl
new file mode 100755
index 0000000000..078217d02b
--- /dev/null
+++ b/challenge-189/bruce-gray/perl/ch-1.pl
@@ -0,0 +1,24 @@
+#!/usr/bin/env perl
+use v5.36;
+use List::Util qw<minstr>;
+
+sub task1 ( $aref, $target ) {
+ my @gt = grep { $_ gt $target } @{$aref};
+
+ return @gt ? minstr(@gt) : $target;
+}
+
+
+my @tests = (
+ [ [qw<e m u g>], 'b', 'e' ],
+ [ [qw<d c e f>], 'a', 'c' ],
+ [ [qw<j a r >], 'o', 'r' ],
+ [ [qw<d c a f>], 'a', 'c' ],
+ [ [qw<t g a l>], 'v', 'v' ],
+);
+use Test::More;
+plan tests => 0+@tests;
+for (@tests) {
+ my ( $aref, $target, $expected ) = @{$_};
+ is task1($aref, $target), $expected, "task1(qw<@{$aref}>)";
+}
diff --git a/challenge-189/bruce-gray/perl/ch-2.pl b/challenge-189/bruce-gray/perl/ch-2.pl
new file mode 100755
index 0000000000..0c15094764
--- /dev/null
+++ b/challenge-189/bruce-gray/perl/ch-2.pl
@@ -0,0 +1,58 @@
+#!/usr/bin/env perl
+use v5.36;
+use experimental qw<for_list builtin>;
+use builtin qw<indexed>;
+use List::UtilsBy qw<max_by min_by>;
+
+# See blog post for shorter code using List::Categorize.
+sub task2 ( @a ) {
+ my %h;
+ for my ($k, $v) (indexed @a) {
+ my $href = ( $h{$v} //= {} );
+
+ $href->{KEY } = $v;
+ $href->{COUNT} += 1;
+ $href->{FIRST} //= $k;
+ $href->{LAST } = $k;
+ }
+ $_->{SPAN} = $_->{LAST} - $_->{FIRST} + 1 for values %h;
+
+ my $best = min_by { $_->{FIRST} }
+ min_by { $_->{SPAN } }
+ max_by { $_->{COUNT} }
+ values %h;
+
+ return [ @a[ $best->{FIRST} .. $best->{LAST} ] ];
+}
+
+
+my @tests = (
+ # From TWC examples:
+ [ [ 1, 3, 3, 2 ] , [ 3, 3 ] ],
+ [ [ 1, 2, 1, 3 ] , [ 1, 2, 1 ] ],
+ [ [ 1, 3, 2, 1, 2 ] , [ 2, 1, 2 ] ],
+ [ [ 1, 1, 2, 3, 2 ] , [ 1, 1 ] ],
+ [ [ 2, 1, 2, 1, 1 ] , [ 1, 2, 1, 1 ] ],
+
+ # TWC examples translated to alpha, for easier debugging.
+ [ [qw<A C C B >] , [qw<C C> ] ],
+ [ [qw<A B A C >] , [qw<A B A> ] ],
+ [ [qw<A C B A B>] , [qw<B A B> ] ],
+ [ [qw<A A B C B>] , [qw<A A> ] ],
+ [ [qw<B A B A A>] , [qw<A B A A>] ],
+
+ # Numeric and alpha versions to stress tie-breaking rules:
+ [ [qw<1 1 2 2 2 2 1 1> ] , [qw<2 2 2 2>] ],
+ [ [qw<A A B B B B A A> ] , [qw<B B B B>] ],
+ [ [qw<1 1 1 1 2 2 2 2> ] , [qw<1 1 1 1>] ],
+ [ [qw<A A A A B B B B> ] , [qw<A A A A>] ],
+ [ [qw<1 1 1 1 2 3 2 2 2> ] , [qw<1 1 1 1>] ],
+ [ [qw<A A A A B C B B B> ] , [qw<A A A A>] ],
+
+);
+use Test::More;
+plan tests => 0+@tests;
+for (@tests) {
+ my ( $in_aref, $expected_aref ) = @{$_};
+ is_deeply task2(@{$in_aref}), $expected_aref, "task2(qw<@{$in_aref}>)";
+}
diff --git a/challenge-189/bruce-gray/raku/ch-1.raku b/challenge-189/bruce-gray/raku/ch-1.raku
new file mode 100644
index 0000000000..8326be5886
--- /dev/null
+++ b/challenge-189/bruce-gray/raku/ch-1.raku
@@ -0,0 +1,20 @@
+sub task1 ( @a, Str $target --> Str ) {
+ return .elems ?? .min !! $target given @a.grep( * gt $target );
+
+ # Single-pass too-clever alternative:
+ # return @a.min({ $_ !gt $target, $_ }) max $target;
+}
+
+
+my @tests =
+ ( <e m u g>, 'b', 'e' ),
+ ( <d c e f>, 'a', 'c' ),
+ ( <j a r >, 'o', 'r' ),
+ ( <d c a f>, 'a', 'c' ),
+ ( <t g a l>, 'v', 'v' ),
+ ;
+use Test;
+plan +@tests;
+for @tests -> ( @array, $target, $expected ) {
+ is task1( @array, $target), $expected, "task1(<@array[]>)";
+}
diff --git a/challenge-189/bruce-gray/raku/ch-2.raku b/challenge-189/bruce-gray/raku/ch-2.raku
new file mode 100644
index 0000000000..c0612139cc
--- /dev/null
+++ b/challenge-189/bruce-gray/raku/ch-2.raku
@@ -0,0 +1,39 @@
+sub task2 ( @a ) {
+ my $best =
+ @a.pairs # index => element
+ .classify( {.value}, :as{.key} ) # element_A => [Ai0, Ai1, … Ai_last], …
+ .map({ .value }) # [Ai0, Ai1, … Ai_last], [Bi0, Bi1, … Bi_last], …
+ .max({ .elems, -(.tail - .head + 1), -.head }); # Highest degree with lowest slice_size
+
+ return @a[ $best.head .. $best.tail ];
+}
+
+
+my @tests =
+ # From TWC examples:
+ ( (1, 3, 3, 2) , (3, 3) ),
+ ( (1, 2, 1, 3) , (1, 2, 1) ),
+ ( (1, 3, 2, 1, 2) , (2, 1, 2) ),
+ ( (1, 1, 2, 3, 2) , (1, 1) ),
+ ( (2, 1, 2, 1, 1) , (1, 2, 1, 1) ),
+
+ # TWC examples translated to alpha, for easier debugging.
+ ( <A C C B > , <C C> ),
+ ( <A B A C > , <A B A> ),
+ ( <A C B A B> , <B A B> ),
+ ( <A A B C B> , <A A> ),
+ ( <B A B A A> , <A B A A> ),
+
+ # Numeric and alpha versions to stress tie-breaking rules:
+ ( <1 1 2 2 2 2 1 1> , <2 2 2 2> ),
+ ( <A A B B B B A A> , <B B B B> ),
+ ( <1 1 1 1 2 2 2 2> , <1 1 1 1> ),
+ ( <A A A A B B B B> , <A A A A> ),
+ ( <1 1 1 1 2 3 2 2 2> , <1 1 1 1> ),
+ ( <A A A A B C B B B> , <A A A A> ),
+;
+use Test;
+plan +@tests;
+for @tests -> ( @array, @expected ) {
+ is-deeply task2(@array), @expected, "task2(<@array[]>)";
+}