forked from manwar/perlweeklychallenge-club
/
ch-2.raku
executable file
·110 lines (93 loc) · 2.4 KB
/
ch-2.raku
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
#!/usr/bin/raku
sub unprefix(Str $num) {
my $unprefixed = $num;
my @from = qw/ CM CD XC XL IX IV /;
my @to = qw/ DCCCC CCCC LXXXX XXXX VIIII IIII /;
for 0 ..^ @from.elems -> $i {
$unprefixed = $unprefixed.subst(@from[$i], @to[$i], :g);
}
return $unprefixed;
}
sub normalize(Str $num) {
my $normalized = $num;
my @from = qw/ IIIII IIII VV VIV XXXXX XXXX LL LXL CCCCC CCCC DD DCD /;
my @to = qw/ V IV X IX L XL C XC D CD M CM /;
for 0 .. @from.end -> $i {
$normalized = $normalized.subst(@from[$i], @to[$i], :g);
}
return $normalized;
}
sub toEnglish($num) {
my %values = (
'M' => 1000,
'D' => 500,
'C' => 100,
'L' => 50,
'X' => 10,
'V' => 5,
'I' => 1,
);
my $english = 0;
for unprefix($num).comb -> $digit {
$english += %values{$digit};
}
return $english;
}
sub toRoman($num is copy) {
my $roman;
while $num > 0 {
if $num >= 1000 {
$roman ~= 'M';
$num -= 1000;
}
elsif $num >= 500 {
$roman ~= 'D';
$num -= 500;
}
elsif $num >= 100 {
$roman ~= 'C';
$num -= 100;
}
elsif $num >= 50 {
$roman ~= 'L';
$num -= 50;
}
elsif $num >= 10 {
$roman ~= 'X';
$num -= 10;
}
elsif $num >= 5 {
$roman ~= 'V';
$num -= 5;
}
elsif $num >= 1 {
$roman ~= 'I';
$num -= 1;
}
}
return normalize($roman);
}
sub MAIN(
Str $arg1, #= Number in Roman numerals
Str $op, #= Arithmetic operation (+, -, *, / or **)
Str $arg2, #= Number in Roman numerals
) {
my $val;
my $eng1 = toEnglish($arg1);
my $eng2 = toEnglish($arg2);
given $op {
when '+' { $val = $eng1 + $eng2; }
when '-' { $val = $eng1 - $eng2; }
when '*' { $val = $eng1 * $eng2; }
when '/' { $val = $eng1 / $eng2; }
when '**' { $val = $eng1 ** $eng2; }
default { &*USAGE(); }
}
given $val {
when $_ == 0 { say 'nulla'; }
when $_ != $_.Int { say 'non potest'; }
when $_ <= 0 { say 'non potest'; }
when $_ >= 4000 { say 'non potest'; }
default { say toRoman($val); }
}
}