From d0502ea7a89dbcc2eaeba364c81cc5aba7b83304 Mon Sep 17 00:00:00 2001 From: Util Date: Sun, 17 Dec 2023 15:07:18 -0600 Subject: Add TWC 247 solutions by Bruce Gray (in Raku only). --- challenge-247/bruce-gray/raku/ch-1.raku | 90 +++++++++++++++++++++++++++++++++ challenge-247/bruce-gray/raku/ch-2.raku | 16 ++++++ 2 files changed, 106 insertions(+) create mode 100644 challenge-247/bruce-gray/raku/ch-1.raku create mode 100644 challenge-247/bruce-gray/raku/ch-2.raku diff --git a/challenge-247/bruce-gray/raku/ch-1.raku b/challenge-247/bruce-gray/raku/ch-1.raku new file mode 100644 index 0000000000..c043e2d732 --- /dev/null +++ b/challenge-247/bruce-gray/raku/ch-1.raku @@ -0,0 +1,90 @@ +# This code is a hot mess, and lots of corner cases are not covered. +# Also, the task examples showed mutual (paired) exchange, +# but that is not how Secret Santa is usually played, +# so I have a boolean PAIR flag for that. + +use Adverb::Eject; +# constant $PAIR = True; +constant $PAIR = False; + +proto task1 ( | ) { * } +multi sub task1 ( @n where 0 ) { Empty } +multi sub task1 ( @n where 1 ) { @n[0] => @n[0] } +multi sub task1 ( @n where 2 ) { @n[0] => @n[1], + @n[1] => @n[0] } +multi sub task1 ( @n where 3 ) { @n[0] => @n[1], + @n[1] => @n[2], + @n[2] => @n[0] } + +multi sub task1 (@names) { + my @c = @names.classify(*.words[1]).map({ .value.pick(*).Array }).pick(*).flat; + + my @ret; + if @c.elems !%% 2 { + my $first = @c.shift; + my $last = @c.pop; + my $half = @c.end div 2; + my $mid = @c[$half]; @c[$half]:eject; + + @ret.append: |samewith([$first, $mid, $last]); + } + + # @n.elems is now even. + @ret.append: |pair_or_chain(@c); + + return @ret; +} +sub pair_or_chain ( @names ) { + die unless @names %% 2; + + # @a is passed in grouped order. + # By creating with pairings half-the-size-of-the-list distance away, + # we minimize the number of inter-group pairings + my $half = @names.elems div 2; + my @a = @names.head($half); + my @b = @names.tail($half); + + return |(@a Z=> @b), |(@b Z=> @a) if $PAIR; + + my @cycle = (@a Z @b).flat; + push @cycle, @a.head; + + return @cycle.rotor(2 => -1).map({ .[0] => .[1] }); +} +my @examples = + ( + 'Mr. Wall', + 'Mrs. Wall', + 'Mr. Anwar', + 'Mrs. Anwar', + 'Mr. Conway', + 'Mr. Cross', + ), + ( + 'Mr. Wall', + 'Mrs. Wall', + 'Mr. Anwar', + ), + # Example from Peter Campbell Smith + ( + 'Rudolph Reindeer', + 'Dasher Reindeer', + 'Dancer Reindeer', + 'Prancer Reindeer', + 'Vixen Reindeer', + 'Comet Reindeer', + 'Cupid Reindeer', + 'Donner Reindeer', + 'Blitzen Reindeer', + 'Santa Claus', + 'Mrs. Claus', + 'Subordinate Claus', + ), +; + +# XXX Not really testing this time, just exercising the examples. +# use Test; plan @tests; +for @examples -> @names { + say ''; + .say for task1(@names); +} diff --git a/challenge-247/bruce-gray/raku/ch-2.raku b/challenge-247/bruce-gray/raku/ch-2.raku new file mode 100644 index 0000000000..d7c99ebf1c --- /dev/null +++ b/challenge-247/bruce-gray/raku/ch-2.raku @@ -0,0 +1,16 @@ +sub task2 ( Str $s --> Str ) { + return $s.comb.rotor(2 => -1)».join.Bag.maxpairs».key.min; + + # Or, use the min-of-negative trick to remove `.maxpairs».key` : + # return $s.comb.rotor(2 => -1)».join.Bag.min({ -.value, .key }).key; +} + + +my @tests = + , + , +; +use Test; plan @tests; +for @tests -> ($expected, $in) { + is task2($in), $expected, $in; +} -- cgit