From c4f9b3fed92acf5b4467448388b955121bd14d98 Mon Sep 17 00:00:00 2001 From: Util Date: Sun, 23 Apr 2023 14:07:29 -0500 Subject: Add TWC 213 solutions by Bruce Gray (Raku only). --- challenge-213/bruce-gray/raku/ch-1.raku | 27 +++++++++++++ challenge-213/bruce-gray/raku/ch-2.raku | 68 +++++++++++++++++++++++++++++++++ 2 files changed, 95 insertions(+) create mode 100644 challenge-213/bruce-gray/raku/ch-1.raku create mode 100644 challenge-213/bruce-gray/raku/ch-2.raku diff --git a/challenge-213/bruce-gray/raku/ch-1.raku b/challenge-213/bruce-gray/raku/ch-1.raku new file mode 100644 index 0000000000..91c685cbe4 --- /dev/null +++ b/challenge-213/bruce-gray/raku/ch-1.raku @@ -0,0 +1,27 @@ +sub task1 { @^ns.sort: { $_ !%% 2, $_ } } + + +# This `classify+map(sort)` might be more efficient for very large elements count +# with roughly equal-sized even/odd partitions. +# +# Note that there is no need to expand the classifying expression +# (like `$_ %% 2 ?? 'even' !! 'odd'` or `[$_ %% 2]`), +# because .classify is not coercing the keys into Str; Bool works just fine for classifying. +# +# We do have to add `if .so` in the `map`, because the input might have no evens or no odds. +# +sub task1_maybe_more_efficient_I_dont_know_I_did_not_benchmark_it ( @ns ) { + return @ns.classify(* %% 2).{True, False}.map({ .sort if .so }).flat; +} + + +my @tests = + ( (1,2,3,4,5,6) , (2,4,6,1,3,5) ), + ( (1,2) , (2,1) ), + ( (1,) , (1,) ), +; +use Test; +plan +@tests; +for @tests -> ( $in, $expected ) { + is-deeply task1($in), $expected; +} diff --git a/challenge-213/bruce-gray/raku/ch-2.raku b/challenge-213/bruce-gray/raku/ch-2.raku new file mode 100644 index 0000000000..073ede5eb3 --- /dev/null +++ b/challenge-213/bruce-gray/raku/ch-2.raku @@ -0,0 +1,68 @@ +sub shortest-path-BFS ( $start-node, $stop-node, %adjacency-list --> List ) { + my @queue = ( $start-node, ); + + my %visited is SetHash = $start-node => True; + + while @queue { + my @path = @queue.shift.list; + my $node = @path.tail; + + return @path.List if $node eq $stop-node; + + for %adjacency-list{$node}.list -> $neighbour { + @queue.push: (flat @path, $neighbour) if !%visited{$neighbour}; + %visited{$neighbour} = True; + } + } + return Nil; +} +sub make-adjacency-list ( @routes ) { + my %adj; # Hash of Lists. Any list could contain duplicates. + for @routes -> @chain-of-routes { + for @chain-of-routes.rotor(2 => -1) { + %adj{ .[0] }.push: .[1]; + %adj{ .[1] }.push: .[0]; + } + } + # Using a unique sorted list instead of a HoH allows us to have + # a stable predicable single expected output for any test case + # that actually has multiple possible shortest-paths. + return %adj.map: { .key => .value.sort.squish }; +} +sub task2 ( $start, $stop, @routes_LoL ) { + my %aL = make-adjacency-list(@routes_LoL); + return shortest-path-BFS( $start, $stop, %aL ) // -1; +} + + +my @tests = + ( 1, 7, ( (1,2,6), (5,6,7) ), (1,2,6,7) ), + ( 2, 5, ( (1,2,3), (4,5,6) ), -1 ), + ( 1, 7, ( (1,2,3), (4,5,6), (3,8,9), (7,8) ), (1,2,3,8,7) ), + + # Same three tests from original task, as letters. + ( 'A', 'G', ( , ), ), + ( 'B', 'E', ( , ), -1 ), + ( 'A', 'G', ( , , , ), ), + + # From mark-anderson , The graph from https://www.youtube.com/watch?v=T_m27bhVQQQ&t=360s + ( 'A', 'H', ( , , , + , , + , , , + , , , + , , + , , , , + , , + , , ), ), + # Same, with edges only given in pairs. + ( 'A', 'H', ( , , , , , , , , , ), ), + # Same, in further reduced form. + ( 'A', 'H', ( , , ), ), + # Same, in single path (but visiting nodes more than once). + ( 'A', 'H', ( , ), ), +; +use Test; +plan +@tests; +for @tests -> ( $start, $stop, $routes, $expected ) { + is-deeply task2( $start, $stop, $routes ), $expected; +} -- cgit