diff options
| author | 冯昶 <fengchang@novel-supertv.com> | 2023-08-30 15:34:26 +0800 |
|---|---|---|
| committer | 冯昶 <fengchang@novel-supertv.com> | 2023-08-30 15:34:26 +0800 |
| commit | 8d6e1060d389ab9bd2d9732d3b9441ed6fd0bf38 (patch) | |
| tree | a9c07316a75f666c072748e621de187ad75b5c8d | |
| parent | 7bdb6e1be5f74137c59ba5b6c302f5c954819240 (diff) | |
| download | perlweeklychallenge-club-8d6e1060d389ab9bd2d9732d3b9441ed6fd0bf38.tar.gz perlweeklychallenge-club-8d6e1060d389ab9bd2d9732d3b9441ed6fd0bf38.tar.bz2 perlweeklychallenge-club-8d6e1060d389ab9bd2d9732d3b9441ed6fd0bf38.zip | |
challenge 227, raku solutions
| -rwxr-xr-x | challenge-227/feng-chang/raku/ch-1.raku | 5 | ||||
| -rwxr-xr-x | challenge-227/feng-chang/raku/ch-2.raku | 126 | ||||
| -rwxr-xr-x | challenge-227/feng-chang/raku/test.raku | 26 |
3 files changed, 157 insertions, 0 deletions
diff --git a/challenge-227/feng-chang/raku/ch-1.raku b/challenge-227/feng-chang/raku/ch-1.raku new file mode 100755 index 0000000000..1865dd913e --- /dev/null +++ b/challenge-227/feng-chang/raku/ch-1.raku @@ -0,0 +1,5 @@ +#!/bin/env raku + +unit sub MAIN(UInt:D $year where 1753 ≤ * ≤ 9999); + +put (1..12).grep({ Date("$year-{ .fmt('%02d') }-13").day-of-week == 5 }).elems; diff --git a/challenge-227/feng-chang/raku/ch-2.raku b/challenge-227/feng-chang/raku/ch-2.raku new file mode 100755 index 0000000000..a1649601c5 --- /dev/null +++ b/challenge-227/feng-chang/raku/ch-2.raku @@ -0,0 +1,126 @@ +#!/bin/env raku + +my @RomanNumerals = <I V X L C D M>; +my %Roman2Digits = @RomanNumerals Z=> +«<1 5 10 50 100 500 1000>; + +grammar RomanExpr { + rule TOP { <Number> <Op> <Number> } + rule Number { <RomanDigit>+ } + + token RomanDigit { 'I' || 'V' || 'X' || 'L' || 'C' || 'D' || 'M' } + token Op { '**' || '+' || '-' || '*' || '/' } +} + +# returns sign of the corresponding Roman digit +proto LessThanRight(UInt:D \ndx, *@nums --> Int:D) {*} + +multi LessThanRight(\ndx, *@nums where ndx ≥ +@nums - 1) { 1 } + +multi LessThanRight(\ndx, *@nums) { + my $ndx_ = ndx; + + while $ndx_ < +@nums - 1 { + if @nums[$ndx_] < @nums[$ndx_+1] { + return -1; + } elsif @nums[$ndx_] > @nums[$ndx_+1] { + return 1; + } + + ++$ndx_; + } + + 1 +} + +class RomanExprActions { + method TOP($/) { + given $<Op> { + when '+' { + my $sum = [+] $<Number>».made; + make $sum ≤ 3999 ?? $sum !! 'non potest' + } + + when '*' { + my $prod = [*] $<Number>».made; + make $prod ≤ 3999 ?? $prod !! 'non potest' + } + + when '**' { + my $pow = $<Number>[0].made ** $<Number>[1].made; + make $pow ≤ 3999 ?? $pow !! 'non potest' + } + + when '-' { + my $diff = [-] $<Number>».made; + given $diff { + when 0 { make 'nulla' } + when $_ < 0 { make 'non potest' } + default { make $diff } + } + } + + when '/' { + my $quot = $<Number>[0].made div $<Number>[1].made; + make ($quot * $<Number>[1].made == $<Number>[0].made) ?? $quot !! 'non potest' + } + } + } + + method RomanDigit($/) { make $/.Str } + method Number($/) { + my @numbers = %Roman2Digits{$<RomanDigit>».made}; + make [+] (^+@numbers).map({ LessThanRight($_, @numbers) * @numbers[$_] }) + } +} + +my %Digits2Roman = + |([1..9] Z=> <I II III IV V VI VII VIII IX>).Hash, + |([1..9] »*» 10 Z=> <X XX XXX XL L LX LXX LXXX XC>).Hash, + |([1..9] »*» 100 Z=> <C CC CCC CD D DC DCC DCCC CM>).Hash, + |([1..3] »*» 1000 Z=> <M MM MMM>).Hash; + +multi Decimal2Roman(UInt:D $n where 1000 ≤ * ≤ 3999) { %Digits2Roman{$n div 1000 * 1000} ~ Decimal2Roman($n mod 1000) } +multi Decimal2Roman(UInt:D $n where 100 ≤ * ≤ 999) { %Digits2Roman{$n div 100 * 100} ~ Decimal2Roman($n mod 100) } +multi Decimal2Roman(UInt:D $n where 10 ≤ * ≤ 99) { %Digits2Roman{$n div 10 * 10} ~ Decimal2Roman($n mod 10) } +multi Decimal2Roman(UInt:D $d where 1 ≤ * ≤ 9) { %Digits2Roman{$d} } +multi Decimal2Roman($msg) { $msg } + +multi MAIN('test') { + use Test; + + is RomanExpr.parse('I', :rule('Number'), :actions(RomanExprActions)).made, 1, 'I => 1'; + is RomanExpr.parse('II', :rule('Number'), :actions(RomanExprActions)).made, 2, 'II => 2'; + is RomanExpr.parse('III', :rule('Number'), :actions(RomanExprActions)).made, 3, 'III => 3'; + is RomanExpr.parse('IV', :rule('Number'), :actions(RomanExprActions)).made, 4, 'IV => 4'; + is RomanExpr.parse('V', :rule('Number'), :actions(RomanExprActions)).made, 5, 'V => 5'; + is RomanExpr.parse('VI', :rule('Number'), :actions(RomanExprActions)).made, 6, 'VI => 6'; + is RomanExpr.parse('VII', :rule('Number'), :actions(RomanExprActions)).made, 7, 'VII => 7'; + is RomanExpr.parse('VIII', :rule('Number'), :actions(RomanExprActions)).made, 8, 'VIII => 8'; + is RomanExpr.parse('IX', :rule('Number'), :actions(RomanExprActions)).made, 9, 'IX => 9'; + is RomanExpr.parse('X', :rule('Number'), :actions(RomanExprActions)).made, 10, 'X => 10'; + + is RomanExpr.parse('DCLVIII', :rule('Number'), :actions(RomanExprActions)).made, 658, 'DCLVIII => 658'; + is RomanExpr.parse('M', :rule('Number'), :actions(RomanExprActions)).made, 1000, 'M => 1000'; + is RomanExpr.parse('CMXCIX', :rule('Number'), :actions(RomanExprActions)).made, 999, 'CMXCIX => 999'; + is RomanExpr.parse('MMMCMXCIX', :rule('Number'), :actions(RomanExprActions)).made, 3999, 'MMMCMXCIX => 3999'; + + is RomanExpr.parse('V + VI', :actions(RomanExprActions)).made, 11, 'V + VI => 11'; + is RomanExpr.parse('IV + V', :actions(RomanExprActions)).made, 9, 'IV + V => 9'; + is RomanExpr.parse('M - I', :actions(RomanExprActions)).made, 999, 'M - I => 999'; + is RomanExpr.parse('X / II', :actions(RomanExprActions)).made, 5, 'X / II => 5'; + is RomanExpr.parse('XI * VI', :actions(RomanExprActions)).made, 66, 'XI * VI => 66'; + is RomanExpr.parse('VII ** III', :actions(RomanExprActions)).made, 343, 'VII ** III => 343'; + is RomanExpr.parse('V - V', :actions(RomanExprActions)).made, 'nulla', "V - V => nulla(they knew about zero but didn't have a symbol)"; + is RomanExpr.parse('V / II', :actions(RomanExprActions)).made, 'non potest', "V / II => non potest(they didn't do fractions)"; + is RomanExpr.parse('MMM + M', :actions(RomanExprActions)).made, 'non potest', 'MMM + M => non potest(they only went up to 3999)'; + is RomanExpr.parse('V - X', :actions(RomanExprActions)).made, 'non potest', "V - X => non potest(they didn't do negative numbers)"; + + is Decimal2Roman(5), 'V', '5 => V'; + is Decimal2Roman(3999), 'MMMCMXCIX', '3999 => MMMCMXCIX'; + + done-testing; +} + +multi MAIN(Str:D $expr) { + put Decimal2Roman(RomanExpr.parse($expr, :actions(RomanExprActions)).made); +} diff --git a/challenge-227/feng-chang/raku/test.raku b/challenge-227/feng-chang/raku/test.raku new file mode 100755 index 0000000000..569856a26a --- /dev/null +++ b/challenge-227/feng-chang/raku/test.raku @@ -0,0 +1,26 @@ +#!/bin/env raku + +# The Weekly Challenge 227 +use Test; + +sub pwc-test(Str:D $script, *@input) { + my ($expect, $assertion) = @input.splice(*-2, 2); + my $p = run $script, |@input, :out; + is $p.out.slurp(:close).chomp, $expect, $assertion; +} + +# Task 1, Friday 13th +pwc-test './ch-1.raku', 2023, 2, 'Friday 13th: 2023 => 2'; + +# Task 2, Roman Maths +pwc-test './ch-2.raku', 'IV + V', 'IX', 'Roman Maths: IV + V => IX'; +pwc-test './ch-2.raku', 'M - I', 'CMXCIX', 'Roman Maths: M - I => CMXCIX'; +pwc-test './ch-2.raku', 'X / II', 'V', 'Roman Maths: X / II => V'; +pwc-test './ch-2.raku', 'XI * VI', 'LXVI', 'Roman Maths: XI * VI => LXVI'; +pwc-test './ch-2.raku', 'VII ** III', 'CCCXLIII', 'Roman Maths: VII ** III => CCCXLIII'; +pwc-test './ch-2.raku', 'V - V', 'nulla', 'Roman Maths: V - V => nulla'; +pwc-test './ch-2.raku', 'V / II', 'non potest', 'Roman Maths: V / II => non potest'; +pwc-test './ch-2.raku', 'MMM + M', 'non potest', 'Roman Maths: MMM + M => non potest'; +pwc-test './ch-2.raku', 'V - X', 'non potest', 'Roman Maths: V - X => non potest'; + +done-testing; |
