DEV Community

Simon Green
Simon Green

Posted on

Weekly Challenge 227

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.

Challenge, My solutions

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
Enter fullscreen mode Exit fullscreen mode

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]
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

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', ],
]
Enter fullscreen mode Exit fullscreen mode

and then iterate backwards to get the correct roman number.

for i, d in enumerate(number[::-1]):
    roman = mapping[i][int(d)] + roman
Enter fullscreen mode Exit fullscreen mode

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
Enter fullscreen mode Exit fullscreen mode

Top comments (0)