aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Sajid Anwar <Mohammad.Anwar@yahoo.com>2024-04-29 00:13:20 +0100
committerGitHub <noreply@github.com>2024-04-29 00:13:20 +0100
commita22ea6213e4a89213f4ccd1d40ab34d989d2fe78 (patch)
tree171d9a7f81cbdda29fcf1f1723a0294028749d9d
parentc7f7a2a52657cb1dc6aa7be06320b61238ce7c6b (diff)
parent71eba32c638f5ebd9a8b077bad5bcda82c07e238 (diff)
downloadperlweeklychallenge-club-a22ea6213e4a89213f4ccd1d40ab34d989d2fe78.tar.gz
perlweeklychallenge-club-a22ea6213e4a89213f4ccd1d40ab34d989d2fe78.tar.bz2
perlweeklychallenge-club-a22ea6213e4a89213f4ccd1d40ab34d989d2fe78.zip
Merge pull request #10006 from Util/c266
Add TWC 266 solutions by Bruce Gray, in Raku only.
-rw-r--r--challenge-266/bruce-gray/raku/ch-1.raku50
-rw-r--r--challenge-266/bruce-gray/raku/ch-2.raku88
2 files changed, 138 insertions, 0 deletions
diff --git a/challenge-266/bruce-gray/raku/ch-1.raku b/challenge-266/bruce-gray/raku/ch-1.raku
new file mode 100644
index 0000000000..f655e6fc5b
--- /dev/null
+++ b/challenge-266/bruce-gray/raku/ch-1.raku
@@ -0,0 +1,50 @@
+# Just as easy to solve this task for any number of lines, instead of just two.
+
+# Common code for "list elements occuring only once".
+constant &non-dups = *.Bag.grep( *.value == 1 )».key;
+
+# Solves the problem along the lines of the actual description of the task.
+sub task1_reduce ( @lines ) {
+ return @lines.map( *.words.&non-dups ).reduce(&[⊎]).&non-dups || '';
+}
+
+# Re-thinking the task,
+# it becomes clear that the distinction between lines in irrelevant;
+# what is wanted are the words that only occur once in any line.
+# Restated:
+# A word is uncommon
+# if it appears exactly once in one of the sentences
+# and doesn’t appear in other sentence.
+# is logically mappable to:
+# A word is uncommon
+# if it appears exactly once
+# across all of the sentences.
+sub task1_rethought ( @lines ) {
+ return @lines».words.flat.&non-dups || '';
+}
+
+sub task1_set_subtraction ( @lines ) {
+ # return keys( .list ∖ .repeated ) || '' given @lines».words.flat.cache; # One-liner; needlessly obtuse.
+
+ my @w = @lines».words.flat;
+
+ return ( @w (-) @w.repeated ).keys || '';
+}
+
+
+constant @tests =
+ ( 'Mango is sweet' , 'Mango is sour' , ( 'sweet', 'sour' ) ),
+ ( 'Mango Mango' , 'Orange' , ( 'Orange', ) ),
+ ( 'Mango is Mango' , 'Orange is Orange' , ( '', ) ),
+;
+constant @subs =
+ :&task1_reduce,
+ :&task1_rethought,
+ :&task1_set_subtraction,
+;
+use Test; plan +@tests * +@subs;
+for @subs -> ( :key($sub_name), :value(&task1) ) {
+ for @tests -> ( $line1, $line2, @expected ) {
+ is-deeply task1(($line1, $line2)).sort, @expected.sort, "$sub_name : $line1";
+ }
+}
diff --git a/challenge-266/bruce-gray/raku/ch-2.raku b/challenge-266/bruce-gray/raku/ch-2.raku
new file mode 100644
index 0000000000..a4739b0afd
--- /dev/null
+++ b/challenge-266/bruce-gray/raku/ch-2.raku
@@ -0,0 +1,88 @@
+# Walk the matrix once, noting by coordinate whether the cell
+# is on either of the diagonals.
+# Early return on first cell containing the wrong (zero/non-zero) value.
+sub task2_efficient ( @mat --> Bool ) {
+ die "Ill-defined for matrix of size zero" unless @mat.elems;
+ die "Not square" unless @mat.elems == @mat».elems.all;
+
+ for @mat.kv -> $i, @row {
+ for @row.kv -> $j, $cell {
+
+ my \is_zero = $cell == 0;
+
+ my \is_diag = $i-$j == 0
+ || $i+$j == @row.end;
+
+ return False if is_diag and is_zero
+ or !is_diag and !is_zero;
+ }
+ }
+
+ return True;
+}
+
+# Pre-calculate all the coordinates of diagonal and anti-diagonal cells.
+# The `unique` removes the doubled coordinate that occurs in the very center of odd-sized matrixes.
+# The `sort` is critical when the use of these coordinates is to modify any row in the bottom half of the matrix.
+sub diagonals_i_j ( $size ) {
+ return (^$size).map({ |(($_, $_), ($_, $size - 1 - $_)) })
+ .unique( :with(&[eqv]) )
+ .sort;
+}
+
+# Find all (i,j) coordinates that are non-zero, and check that they exactly match the diagonals.
+sub task2_concise ( @m --> Bool ) {
+ return diagonals_i_j(+@m) eqv sort grep ->(\i,\j) { @m[i][j] !== 0 }, [X] @m.keys xx 2;
+}
+
+# Clone the matrix, extract the diagonal and anti-diagonal cells from each row and store in a seperate array, then check that all diags are non-zero and the remaining matrix cells are all zero.
+sub task2_copy ( @matrix --> Bool ) {
+ die "Ill-defined for matrix of size zero" unless @matrix.elems;
+ die "Not square" unless @matrix.elems == @matrix».elems.all;
+
+ my @m = @matrix.map({[ .list ]}); # Mutable copy
+
+ # Using gather/take instead of `map` for clarity; @m is mutated in the loop.
+ my @diag_values = gather for diagonals_i_j(+@m).reverse -> (\i,\j) {
+ take @m[i].splice(j, 1).head;
+ }
+
+ return ?( @diag_values.none == 0
+ and @m»<>.flat.all == 0 );
+}
+# There are several hybrids of task2_copy that I did not code here:
+# * Early return during the `gather for` loop.
+# * Setting `@m[i][j]` to `0` after `take`, instead of `.splice`-ing it out.
+# Using `0` would also remove the `.sort` in diagonals_i_j(), and `.reverse` in its call.
+
+
+constant @tests =
+ ( 'Task example 1', True, (
+ (1, 0, 0, 2),
+ (0, 3, 4, 0),
+ (0, 5, 6, 0),
+ (7, 0, 0, 1),
+ )),
+ ( 'Task example 2', False, (
+ (1, 2, 3),
+ (4, 5, 6),
+ (7, 8, 9),
+ )),
+ ( 'Task example 3', True, (
+ (1, 0, 2),
+ (0, 3, 0),
+ (4, 0, 5),
+ )),
+
+;
+constant @subs =
+ :&task2_efficient,
+ :&task2_concise,
+ :&task2_copy,
+;
+use Test; plan +@tests * +@subs;
+for @subs -> ( :key($sub_name), :value(&task2) ) {
+ for @tests -> ( $test_name, $expected, @matrix ) {
+ is task2(@matrix), $expected, "$sub_name : $test_name";
+ }
+}