aboutsummaryrefslogtreecommitdiff
path: root/challenge-010/daniel-mita/perl6
diff options
context:
space:
mode:
authorDaniel Mita <mienaikage@gmail.com>2019-06-01 00:53:36 +0100
committerDaniel Mita <mienaikage@gmail.com>2019-06-01 00:59:48 +0100
commit97b6a24e4b4bbe702b366248bb2c44e49eb5c76a (patch)
tree6b450c8583ae1debd7b081f51b4df86cd5f5d109 /challenge-010/daniel-mita/perl6
parent84c4f932ac5974d2cc10739e2253c70c2d465604 (diff)
downloadperlweeklychallenge-club-97b6a24e4b4bbe702b366248bb2c44e49eb5c76a.tar.gz
perlweeklychallenge-club-97b6a24e4b4bbe702b366248bb2c44e49eb5c76a.tar.bz2
perlweeklychallenge-club-97b6a24e4b4bbe702b366248bb2c44e49eb5c76a.zip
Finish roman numerals
Add values for 4s and 9s Replace from-roman with proper routine Throw in some error messages for good measure
Diffstat (limited to 'challenge-010/daniel-mita/perl6')
-rw-r--r--challenge-010/daniel-mita/perl6/RomanNumerals.pm6106
-rw-r--r--challenge-010/daniel-mita/perl6/ch-1.p650
2 files changed, 94 insertions, 62 deletions
diff --git a/challenge-010/daniel-mita/perl6/RomanNumerals.pm6 b/challenge-010/daniel-mita/perl6/RomanNumerals.pm6
index ba136209ed..7586da106a 100644
--- a/challenge-010/daniel-mita/perl6/RomanNumerals.pm6
+++ b/challenge-010/daniel-mita/perl6/RomanNumerals.pm6
@@ -1,29 +1,87 @@
-unit module RomanNumerals;
-
-constant @letters = 「IVXLCDM」.comb;
-constant @overlines = "\c[combining overline]", "\c[combining double overline]";
-
-constant %letter-map = ( 1, |( * X* 5, 10 ) … ∞ ) Z=>
- |@letters, |( @overlines XR~ @letters[1..*] );
-
-constant %prefixes = %letter-map{ 10 X** 3, 6 } Z=> ( %letter-map<1> X~ @overlines );
-
-sub to-roman (
- UInt() $_ where 0 < * < 4e9,
- --> Str:D
-) is pure is export {
- return [~] gather {
- for .flip.comb.pairs.reverse {
- given 10 ** .key -> $key {
- when .value == 4 | 9 {
- take %prefixes{ %letter-map{$key} } || %letter-map{$key};
- take %letter-map{ $key * (.value + 1) };
+my role X::RomanNumerals is X::AdHoc {}
+
+my class X::RomanNumerals::InvalidRomanString does X::RomanNumerals {
+ method message {
+ "Input 「$.payload」 was not understood.";
+ }
+}
+
+my class X::RomanNumerals::NumberTooLarge does X::RomanNumerals {
+ method message {
+ 'Numbers ≥ 4,000,000,000 not supported.';
+ }
+}
+
+my class X::RomanNumerals::NonPositiveNumber does X::RomanNumerals {
+ method message {
+ 「Can't convert number < 1.」;
+ }
+}
+
+module RomanNumerals {
+
+ constant @letters = 「IVXLCDM」.comb;
+ constant @overlines = "\c[combining overline]", "\c[combining double overline]";
+ constant @letter-pairs = reverse @letters[0],
+ |('', |@overlines).map( @letters X~ * ).map({
+ gather {
+ for .rotor(3 => -1) -> @group {
+ for 1, 2 {
+ take @group[0, $_].join;
+ take @group[$_];
+ }
}
- if .value ≥ 5 {
- take %letter-map{ $key * 5 };
+ }
+ }).flat Z=> ( 1, |( * X* 4, 5, 9, 10 ) … ∞ );
+
+ multi to-roman (
+ Int() $number where 0 < * < 4e9,
+ --> Str:D
+ ) is pure is export {
+ given %(@letter-pairs.Map.antipairs) -> %letter-map {
+ return [~] gather {
+ for $number.flip.comb.pairs.reverse {
+ given 10 ** .key -> $key {
+ when .value == 4 | 9 {
+ take %letter-map{ $key * .value };
+ }
+ take %letter-map{ $key * 5 } if .value ≥ 5;
+ take %letter-map{ $key } x .value % 5;
+ }
+ }
+ };
+ }
+ }
+
+ multi to-roman ( Int() $_ --> Nil ) {
+ when * ≥ 4e9 {
+ X::RomanNumerals::NumberTooLarge.new.throw;
+ }
+ when * < 1 {
+ X::RomanNumerals::NonPositiveNumber.new.throw;
+ }
+ }
+
+ multi from-roman (
+ Str() $roman-string,
+ --> UInt:D
+ ) is pure is export {
+ return [+] gather {
+ my $str = $roman-string.uc;
+ for @letter-pairs -> $pair {
+ if $str ~~ / ^ ( $($pair.key) )+ / {
+ take ($pair.value xx $0).Slip;
+ $str.=substr($0.join.chars);
}
- take %letter-map{ $key } x .value % 5;
}
+ X::RomanNumerals::InvalidRomanString.new(:payload($roman-string)).throw if $str;
}
- };
+ }
+
+ multi from-roman (
+ Str() $_ where { .chars == 0 || .uc.comb ⊈ @letter-pairs.Hash.keys.join.comb },
+ --> Nil
+ ) {
+ X::RomanNumerals::InvalidRomanString.new(:payload($_)).throw
+ }
}
diff --git a/challenge-010/daniel-mita/perl6/ch-1.p6 b/challenge-010/daniel-mita/perl6/ch-1.p6
index 601c2a67e3..21d4dc5ba2 100644
--- a/challenge-010/daniel-mita/perl6/ch-1.p6
+++ b/challenge-010/daniel-mita/perl6/ch-1.p6
@@ -3,53 +3,27 @@ use v6;
use lib $?FILE.IO.dirname;
use RomanNumerals;
-my %*SUB-MAIN-OPTS = :named-anywhere;
+proto MAIN (|) {
+ {*}
+ CATCH {
+ when X::RomanNumerals {
+ say "Error:\n {.message}\n\n" ~ $*USAGE;
+ }
+ }
+}
multi MAIN (
- UInt:D $number where 0 < * < 4e9, #= A positive integer.
+ IntStr() $number, #= A positive integer.
--> Nil
) {
say to-roman($number);
}
-#| Not Yet Implemented
-multi MAIN (
- Str:D $roman-numerals where { $_ !~~ UInt && .chars > 0 }
- --> Nil
-) is hidden-from-USAGE {
- say &?ROUTINE.WHY;
-}
-
multi MAIN (
- Str:D $roman-numerals where { $_ !~~ UInt && .chars > 0 }, #= A string of roman numerals.
- Bool:D :bruteforce(:$b) where *.so, #= Convert using bruteforce method.
+ Str() $roman-numerals, #= A string of roman numerals.
--> Nil
) {
- given |(
- @RomanNumerals::overlines.map( @RomanNumerals::letters X~ * ).reverse
- ), @RomanNumerals::letters -> @set {
- $roman-numerals.uc ~~ / ^ ( @(@set[0])+ )? ( @(@set[1])+ )? ( @(@set[2])+ )? $ /;
+ given from-roman($roman-numerals) -> $result {
+ say $result ~ " (did you mean $_?)" x ($roman-numerals.uc ne $_) given to-roman($result);
}
-
- if $/ {
- given await gather {
- for $/[*].reverse.pairs -> $pair {
- take Promise.start({
- (1..^4000).race.map( * × 10 ** ($pair.key × 3) ).first(*.&to-roman eq $pair.value)
- }) if $pair.value;
- }
- } {
- if .all.so && .sum.&to-roman eq $roman-numerals.uc {
- .sum.say;
- return;
- }
- }
- }
-
- say "Error:\n The input was not understood.\n\n" ~ $*USAGE;
-}
-
-sub GENERATE-USAGE ( &main, |capture ) {
- "Error:\n Numbers ≥ 4,000,000,000 not supported.\n\n"
- x (capture[0] ~~ UInt && capture[0] ≥ 4e9) ~ $*USAGE;
}