diff options
| author | Daniel Mita <mienaikage@gmail.com> | 2019-06-01 00:53:36 +0100 |
|---|---|---|
| committer | Daniel Mita <mienaikage@gmail.com> | 2019-06-01 00:59:48 +0100 |
| commit | 97b6a24e4b4bbe702b366248bb2c44e49eb5c76a (patch) | |
| tree | 6b450c8583ae1debd7b081f51b4df86cd5f5d109 /challenge-010/daniel-mita/perl6 | |
| parent | 84c4f932ac5974d2cc10739e2253c70c2d465604 (diff) | |
| download | perlweeklychallenge-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.pm6 | 106 | ||||
| -rw-r--r-- | challenge-010/daniel-mita/perl6/ch-1.p6 | 50 |
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; } |
