Each week Mohammad S. Anwar sends out The Weekly Challenge, a chance for all of us to come up with solutions to two weekly tasks. My solutions are written in Python first, and then converted to Perl. It's a great way for us all to practice some coding.
Task 1: Friday 13th
Task
You are given a year number in the range 1753 to 9999.
Write a script to find out how many dates in the year are Friday 13th, assume that the current Gregorian calendar applies.
My solution
This is rather straight forward. Create a loop for each month of the year and see if the 13th of the month is a Friday. For Python, I use the date module (from datetime). In Perl, I use Date::Calc.
Examples
$ ./ch-1.py 2023
2
Task 2: Roman Maths
Task
Write a script to handle a 2-term arithmetic operation expressed in Roman numeral.
My solution
The main part of this routine is a method from_roman
which converts a roman number to an integer, and to_roman
which converts a number to a roman number.
The main function converts the two provided numbers into decimals, performs the mathematical operation, and converts the result back to a roman number.
from_roman method
The first thing is to convert the letter to its equivalent number.
mapping = {'I': 1, 'V': 5, 'X': 10, 'L': 50, 'C': 100, 'D': 500, 'M': 1000}
digits = [mapping[s] for s in roman]
I then loop through each value. If the next value is higher, I subtract that from number (as is the case with 'I' in 'IV' or 'IX'), otherwise I add the number.
for i, v in enumerate(digits):
if i < len(digits)-1 and v < digits[i+1]:
number -= v
else:
number += v
This is not perfect. For example MIM
will erroneously return 1999.
to_roman method
The first step is to handle cases where the number is greater than 3999, less than 1 or not a whole number. In this case, I display the appropriate words.
I start by creating a mapping table. Each row represents single digits, tens, hundreds and thousands. Each value represents how to write that number. For example 40 is the 5th value in the 2nd row which is 'XL'.
mapping = [
['', 'I', 'II', 'III', 'IV', 'V', 'VI', 'VII', 'VIII', 'IX', ],
['', 'X', 'XX', 'XXX', 'XL', 'L', 'LX', 'LXX', 'LXXX', 'XC', ],
['', 'C', 'CC', 'CCC', 'CD', 'D', 'DC', 'DCC', 'DCCC', 'CM', ],
['', 'M', 'MM', 'MMM', ],
]
and then iterate backwards to get the correct roman number.
for i, d in enumerate(number[::-1]):
roman = mapping[i][int(d)] + roman
Examples
$ ./ch-2.py IV + V
IX
$ ./ch-2.py M - I
CMXCIX
$ ./ch-2.py X / II
V
$ ./ch-2.py XI '*' VI
LXVI
$ ./ch-2.py VII '**' III
CCCXLIII
$ ./ch-2.py V - V
nulla
$ ./ch-2.py V / II
non potest
$ ./ch-2.py MMM + M
non potest
$ ./ch-2.py V - X
non potest
Top comments (0)