aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMohammad Sajid Anwar <Mohammad.Anwar@yahoo.com>2023-07-31 01:13:29 +0100
committerGitHub <noreply@github.com>2023-07-31 01:13:29 +0100
commitc1c08cce0d2bd79fe3e5dd06fa5ff7007359b02b (patch)
tree28e77fbf0865fa26558a2dc0f42fb3f5f07797fe
parent091aab3405809252ef062e18eaf27dc3fc9202dc (diff)
parent18752bc85eaa5efb37c1a9b1d80eefc2b8653d67 (diff)
downloadperlweeklychallenge-club-c1c08cce0d2bd79fe3e5dd06fa5ff7007359b02b.tar.gz
perlweeklychallenge-club-c1c08cce0d2bd79fe3e5dd06fa5ff7007359b02b.tar.bz2
perlweeklychallenge-club-c1c08cce0d2bd79fe3e5dd06fa5ff7007359b02b.zip
Merge pull request #8469 from Util/c227
Add TWC 227 solutions by Bruce Gray (Raku only).
-rw-r--r--challenge-227/bruce-gray/raku/ch-1.raku30
-rw-r--r--challenge-227/bruce-gray/raku/ch-2.raku66
2 files changed, 96 insertions, 0 deletions
diff --git a/challenge-227/bruce-gray/raku/ch-1.raku b/challenge-227/bruce-gray/raku/ch-1.raku
new file mode 100644
index 0000000000..6c16d3097d
--- /dev/null
+++ b/challenge-227/bruce-gray/raku/ch-1.raku
@@ -0,0 +1,30 @@
+enum DayNames «:Monday(1) Tuesday Wednesday Thursday Friday Saturday Sunday»;
+
+sub task1 ( UInt $year where 1753..9999 --> UInt ) {
+ return +grep { Date.new($year, $_, 13).day-of-week == Friday }, 1..12;
+}
+
+
+constant @tests =
+ ( 1753, 2 ),
+ ( 2023, 2 ),
+ ( 9999, 1 ),
+;
+use Test;
+plan @tests + 1;
+for @tests -> ( UInt $in, UInt $expected ) {
+ is task1($in), $expected;
+}
+ok all map { .&task1_alternate == .&task1 }, 1753..9999;
+
+
+# By observing that the final answer completely depends on the
+# day-of-week of the first day of the year, and whether it is a leap year,
+# we could precompute then replace 12 .day-of-week calls
+# with 1 .day-of-week and 1 .is-leap-year .
+# However, I feel this takes the resulting code
+# too far from the task description.
+sub task1_alternate ( UInt $year --> UInt ) {
+ constant @t = Nil, (2, 2), (2, 1), (1, 2), (3, 2), (1, 1), (1, 1), (2, 3);
+ return @t[ .day-of-week ][ .is-leap-year ] given Date.new(:$year);
+}
diff --git a/challenge-227/bruce-gray/raku/ch-2.raku b/challenge-227/bruce-gray/raku/ch-2.raku
new file mode 100644
index 0000000000..db170711ae
--- /dev/null
+++ b/challenge-227/bruce-gray/raku/ch-2.raku
@@ -0,0 +1,66 @@
+# I spliced together https://rosettacode.org/wiki/Roman_numerals/ and
+# https://andrewshitov.com/2018/10/31/creating-a-calculator-with-perl-6-grammars/
+# , added `**`, trimmed out the calc code that supported PEDMAS precedence and
+# expressions of more than 2 terms, used Int::polydiv to implify because it is
+# perfect for this task, then refactored everything.
+use Int::polydiv;
+constant @r_pairs =
+ M => 1000, CM => 900, D => 500, CD => 400,
+ C => 100, XC => 90, L => 50, XL => 40,
+ X => 10, IX => 9, V => 5, IV => 4,
+ I => 1,
+;
+constant @roman_letters = @r_pairs».key;
+constant @roman_values = @r_pairs».value;
+constant %r = @r_pairs;
+
+constant %operator_sub = < + - * / ** >
+ Z=> &[+], &[-], &[*], &[/], &[**] ;
+constant @operators = %operator_sub.keys;
+
+# The Romans had no symbol for zero,
+# and no numerics for fractions, negatives, or 4000+ .
+multi sub to_roman ( 0 ) { 'nulla' }
+multi sub to_roman ( Rat ) { 'non potest' }
+multi sub to_roman ( Int $n where -∞ ..^ 0 ) { 'non potest' }
+multi sub to_roman ( UInt $n where 4000 ..^ ∞ ) { 'non potest' }
+multi sub to_roman ( UInt $n --> Str ) {
+ return [~] flat @roman_letters Zxx $n.polydiv(@roman_values);
+}
+
+grammar Calc {
+ rule TOP { ^ <expression> $ }
+ rule expression { <term> ** 2 %% <op> }
+ token op { @operators }
+ token term { (@roman_letters)+ }
+}
+class CalcActions {
+ method TOP ($/) { $/.make: $<expression>.ast.narrow }
+ method expression ($/) { $/.make: $<op>[0].ast.( |$<term>.map(*.ast) ) }
+ method op ($/) { $/.make: %operator_sub{ ~$/ } }
+ method term ($/) { $/.make: %r{ $/[0] }.sum }
+}
+
+sub task2 ( Str $to_calculate --> Str ) {
+ my $calc = Calc.parse( $to_calculate, :actions(CalcActions) );
+
+ return $calc.ast.&to_roman;
+}
+
+
+my @tests =
+ ( 'IV + V' , 'IX' ),
+ ( 'M - I' , 'CMXCIX' ),
+ ( 'X / II' , 'V' ),
+ ( 'XI * VI' , 'LXVI' ),
+ ( 'VII ** III' , 'CCCXLIII' ),
+ ( 'V - V' , 'nulla' ),
+ ( 'V / II' , 'non potest' ),
+ ( 'MMM + M' , 'non potest' ),
+ ( 'V - X' , 'non potest' ),
+;
+use Test;
+plan +@tests;
+for @tests -> ( $in, $expected ) {
+ is task2($in), $expected;
+}