diff options
| author | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2023-07-26 23:16:10 +0100 |
|---|---|---|
| committer | Mohammad S Anwar <mohammad.anwar@yahoo.com> | 2023-07-26 23:16:10 +0100 |
| commit | f84f38be0e67c61c44fa0769b00e53124d1bdde0 (patch) | |
| tree | ca3c2b5f833306b7d3b14abb77fda783cdf998cf /challenge-227 | |
| parent | 6a31bf4676dcb9f83b0ef2d91407301686ed0cd8 (diff) | |
| download | perlweeklychallenge-club-f84f38be0e67c61c44fa0769b00e53124d1bdde0.tar.gz perlweeklychallenge-club-f84f38be0e67c61c44fa0769b00e53124d1bdde0.tar.bz2 perlweeklychallenge-club-f84f38be0e67c61c44fa0769b00e53124d1bdde0.zip | |
- Added solutions by Arne Sommer.
- Added solutions by Laurent Rosenfeld.
Diffstat (limited to 'challenge-227')
| -rw-r--r-- | challenge-227/laurent-rosenfeld/blog1.txt | 1 | ||||
| -rw-r--r-- | challenge-227/laurent-rosenfeld/perl/ch-2.pl | 63 | ||||
| -rw-r--r-- | challenge-227/laurent-rosenfeld/raku/ch-2.raku | 57 |
3 files changed, 121 insertions, 0 deletions
diff --git a/challenge-227/laurent-rosenfeld/blog1.txt b/challenge-227/laurent-rosenfeld/blog1.txt new file mode 100644 index 0000000000..66db4bdf8e --- /dev/null +++ b/challenge-227/laurent-rosenfeld/blog1.txt @@ -0,0 +1 @@ +https://blogs.perl.org/users/laurent_r/2023/07/perl-weekly-challenge-227-roman-maths.html diff --git a/challenge-227/laurent-rosenfeld/perl/ch-2.pl b/challenge-227/laurent-rosenfeld/perl/ch-2.pl new file mode 100644 index 0000000000..26470af669 --- /dev/null +++ b/challenge-227/laurent-rosenfeld/perl/ch-2.pl @@ -0,0 +1,63 @@ +#!/usr/bin/perl +use strict; +use warnings; +use feature qw/say/; + +my %rom_tab = (I => 1, V => 5, X => 10, L => 50, + C => 100, D => 500, M => 1000, + IV => 4, IX => 9, XL => 40, XC => 90, + CD => 400, CM => 900); + +sub from_roman { + my $roman = uc shift; + my $arabic = 0; + my $prev_letter = "M"; + for my $letter (split //, $roman) { + $arabic -= 2 * $rom_tab{$prev_letter} + if $rom_tab{$letter} > $rom_tab{$prev_letter}; + $arabic += $rom_tab{$letter}; + $prev_letter = $letter; + } + return $arabic; +} + +sub to_roman { + my $arabic = shift; + warn "$arabic out of bounds" + unless $arabic > 0 and $arabic < 4000; + my $roman = ""; + for my $key (sort { $rom_tab{$b} <=> $rom_tab{$a} } + keys %rom_tab) { + my $num = int ($arabic / $rom_tab{$key}); + $roman .= $key x $num; + $arabic -= $rom_tab{$key} * $num; + } + return $roman; +} +sub process_input { + my ($rom1, $op, $rom2) = split /\s+/, $_[0]; + my $arabic1 = from_roman $rom1; + my $arabic2 = from_roman $rom2; + my $result = $op eq '+' ? $arabic1 + $arabic2 : + $op eq '-' ? $arabic1 - $arabic2 : + $op eq '/' ? $arabic1 / $arabic2 : + $op eq '*' ? $arabic1 * $arabic2 : + $op eq '**' ? $arabic1 ** $arabic2: + "illegal"; + return "nulla (they didn't have a symbol for 0)" + if $result == 0; + return "non potest (they didn't do fractions)" + if int($result) != $result; + return "non potest (they only went up to 3999)" + if $result >= 4000; + return "non potest (no negative numbers)" + if $result < 0; + return to_roman $result; +} + +for my $test ("IV + V", "M - I", "X / II", "XI * VI", + "VII ** III", "V - V", "V / II", "MMM + M", + "V - X ", "X - V") { + printf "%-10s => ", $test; + say process_input $test; +} diff --git a/challenge-227/laurent-rosenfeld/raku/ch-2.raku b/challenge-227/laurent-rosenfeld/raku/ch-2.raku new file mode 100644 index 0000000000..94456d0776 --- /dev/null +++ b/challenge-227/laurent-rosenfeld/raku/ch-2.raku @@ -0,0 +1,57 @@ +subset Roman-str of Str where $_ ~~ /^<[IVXLCDMivxlcdm]>+$/; + +my %rom-tab = < I 1 V 5 X 10 L 50 C 100 D 500 M 1000 + IV 4 IX 9 XL 40 XC 90 CD 400 CM 900 >; +my @ordered_romans = reverse sort { %rom-tab{$_} }, keys %rom-tab; + +sub from-roman (Roman-str $roman) { + my $numeric = 0; + my $prev_letter = "M"; + for $roman.uc.comb -> $letter { + $numeric -= 2 * %rom-tab{$prev_letter} + if %rom-tab{$letter} > %rom-tab{$prev_letter}; + $numeric += %rom-tab{$letter}; + # say "$letter $numeric"; + $prev_letter = $letter; + } + return $numeric; +} + +sub to-roman (Int $arabic is copy where { 0 < $_ < 4000 }) { + my $roman = ""; + for @ordered_romans -> $key { + my $num = ($arabic / %rom-tab{$key}).Int; + $roman ~= $key x $num; + $arabic -= %rom-tab{$key} * $num; + } + return $roman; +} +sub process-input (Str $in) { + my ($rom1, $op, $rom2) = split /\s+/, $in; + my $arabic1 = from-roman $rom1; + my $arabic2 = from-roman $rom2; + my $result; + given $op { + when '+' { $result = $arabic1 + $arabic2 } + when '-' { $result = $arabic1 - $arabic2 } + when '*' { $result = $arabic1 * $arabic2 } + when '/' { $result = $arabic1 / $arabic2 } + when '**' { $result = $arabic1 ** $arabic2 } + } + return "nulla (they didn't have a symbol for 0)" + if $result == 0; + return "non potest (they didn't do fractions)" + if $result.round != $result; + return "non potest (they only went up to 3999)" + if $result >= 4000; + return "non potest (no negative numbers)" + if $result < 0; + return to-roman $result.round; +} + +for "IV + V", "M - I", "X / II", "XI * VI", + "VII ** III", "V - V", "V / II", "MMM + M", + "V - X ", "X - V" -> $test-expr { + printf "%-10s => ", $test-expr; + say process-input $test-expr; +} |
