diff options
| author | Mohammad S Anwar <Mohammad.Anwar@yahoo.com> | 2023-04-10 00:36:29 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-04-10 00:36:29 +0100 |
| commit | 57355f5064046cebfd68a5934fe0d8ec3d881e0b (patch) | |
| tree | 36a8dd79af81c1976a69473b7638642ca989c7b8 /challenge-211 | |
| parent | bee358b75061fd8a86d9d59668dcc1138fab6b23 (diff) | |
| parent | 10f1ed83fc5222e38b57e74b5c404c8af03af7c3 (diff) | |
| download | perlweeklychallenge-club-57355f5064046cebfd68a5934fe0d8ec3d881e0b.tar.gz perlweeklychallenge-club-57355f5064046cebfd68a5934fe0d8ec3d881e0b.tar.bz2 perlweeklychallenge-club-57355f5064046cebfd68a5934fe0d8ec3d881e0b.zip | |
Merge pull request #7876 from Util/c211
Add TWC 211 solutions by Bruce Gray (Raku only).
Diffstat (limited to 'challenge-211')
| -rw-r--r-- | challenge-211/bruce-gray/raku/ch-1.raku | 120 | ||||
| -rw-r--r-- | challenge-211/bruce-gray/raku/ch-2.raku | 58 |
2 files changed, 178 insertions, 0 deletions
diff --git a/challenge-211/bruce-gray/raku/ch-1.raku b/challenge-211/bruce-gray/raku/ch-1.raku new file mode 100644 index 0000000000..754810b1a6 --- /dev/null +++ b/challenge-211/bruce-gray/raku/ch-1.raku @@ -0,0 +1,120 @@ +# Three solutions. + +# My "official" answer to the task. +# For any two adjacent rows, all elements (except the last ) of the first row +# must match all elements (except the first) of the next row. +# With a small refactor to use an iterator and @last&@this rows, +# this would work efficiently with an enormous number of rows. +sub task1 ( @m --> Bool ) { + for @m.rotor( 2 => -1 ) -> ( $top, $bottom ) { + return False unless $top.head(*-1) eqv $bottom.skip(1); + } + return True; +} + +# All credit for this idea goes to Mark Anderson: +# @m[ ^@m.end; ^@m[0].end ] eqv @m[ 1..@m.end; 1..@m[1].end ] +# https://github.com/manwar/perlweeklychallenge-club/blob/master/challenge-211/mark-anderson/raku/ch-1.raku#L24 +# A Toeplitz matrix minus its right and bottom edges will be identical +# to that matrix minus its left and top edges. +# Mark's range-and-semicolon wording is a perfect expression of that idea, if you already know that idea. +# I wrote my version differently, attempting to better convey the idea to those who *don't* already know it. +# Then, I ended up writing all this text anyway, so my success is doubtful. +sub task1_concise ( @m ) { + return @m.head(*-1).map({ .head(*-1) }) # Omitting bottom and right edges. + eqv @m.tail(*-1).map({ .tail(*-1) }); # Omitting top and left edges. +} + + +# This is the first thing I wrote when I read the task. +# Walking each element of the first row, +# it checks that every value matches along the diagonal, +# returning False on a mis-match.all the diagonal values checks each diagonal. +# Since that process misses all the diagonal starting points (besides [0,0]) +# on the left edge of the matrix, the second loop handles those. +sub task1_first_attempt ( @m --> Bool ) { + for @m[0].keys -> $col { + my $first_of_top_edge = @m[0][$col]; + for 1 .. min(@m.end, @m[0].end - $col) -> $row { + return False unless @m[$row][$col+$row] eqv $first_of_top_edge; + } + } + for @m.keys.skip -> $row { + my $first_of_left_edge = @m[$row][0]; + for 1 .. min(@m[0].end, @m.end-$row) -> $col { + return False unless @m[$row+$col][$col] eqv $first_of_left_edge; + } + } + return True; +} + + +my @tests = + ( + ( + < 4 3 2 1 >, + < 5 4 3 2 >, + < 6 5 4 3 >, + ), + True, + ), + ( + ( + < 1 2 3 >, + < 3 2 1 >, + ), + False, + ), + + # Example 1, but final element differs + ( + ( + < 4 3 2 1 >, + < 5 4 3 2 >, + < 6 5 4 9 >, + ), + False, + ), + + ( + ( + < A B C D E F G H I J K >, + < Z A B C D E F G H I J >, + < Y Z A B C D E F G H I >, + < X Y Z A B C D E F G H >, + < W X Y Z A B C D E F G >, + < V W X Y Z A B C D E F >, + < U V W X Y Z A B C D E >, + ), + True, + ), + ( + ( # Just like last test, but `V` on last line now `_` + < A B C D E F G H I J K >, + < Z A B C D E F G H I J >, + < Y Z A B C D E F G H I >, + < X Y Z A B C D E F G H >, + < W X Y Z A B C D E F G >, + < V W X Y Z A B C D E F >, + < U _ W X Y Z A B C D E >, + ), + False, + ), + ( + ( + < A B C >, + < Z A B >, + < Y Z A >, + < X Y Z >, + < W X Y >, + < V W X >, + < U V W >, + ), + True, + ), +; +use Test; +plan +@tests; +for @tests -> ( $in, $expected ) { + is task1($in), $expected; +} diff --git a/challenge-211/bruce-gray/raku/ch-2.raku b/challenge-211/bruce-gray/raku/ch-2.raku new file mode 100644 index 0000000000..c30553b231 --- /dev/null +++ b/challenge-211/bruce-gray/raku/ch-2.raku @@ -0,0 +1,58 @@ +# The average of a solution group will == the average of the whole array. +# The average of a solution group is .sum/.elems, +# and .elems is fixed during each loop of $group_size, +# so we can pre-calculate the sum to search for. +# A further optimization comes from the task specifying that all elements are integers. +# Their sum must be an integer, so if the "target sum" is not an integer, we can skip the whole group of that size. +# e.g. 1..8 has an average of 9/2; a group of size 3 can never average to 9/2, because the divisor will be 3. +sub task2 ( @ns where { @ns.all ~~ Int } --> Bool ) { + my Rat $average = @ns.sum / @ns.elems; + + for 1 .. (@ns.elems div 2) -> $group_size { + + my Rat $target_sum = $average * $group_size; + + next unless $target_sum.denominator == 1; + + return True if @ns.combinations($group_size)ยป.sum.any == $target_sum; + } + + return False; +} + +# This was my first solution. +# Averages are Rats, so `==` need not worry about precision. +# No need to create the second group, since its .sum and its .elems +# can be calculated as the difference from the first group. +sub task2_original ( @ns --> Bool ) { + my $all_sum = @ns.sum; + my $all_elems = @ns.elems; + + for 1 .. (@ns.elems div 2) -> $group_size { + for @ns.combinations($group_size) { + my $sum = .sum; + my $elems = .elems; + + my $average_A = $sum / $elems; + my $average_B = ($all_sum - $sum) / ($all_elems - $elems); + return True if $average_A == $average_B; + } + } + + return False; +} + + +my @tests = + ( ( 1, 2, 3, 4, 5, 6, 7, 8 ), True ), + ( ( 1, 3 ), False ), + + ( ( 1, 3, 1, 3 ), True ), + ( ( 8, 7, 9 ), True ), + ( ( 8, 7, 8 ), False ), +; +use Test; +plan +@tests; +for @tests -> ( $in, $expected ) { + is task2($in), $expected; +} |
