Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- # This program is free software: you can redistribute it and/or modify
- # it under the terms of the GNU General Public License as published by
- # the Free Software Foundation, either version 3 of the License, or
- # (at your option) any later version.
- # This program is distributed in the hope that it will be useful,
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- # GNU General Public License for more details.
- # You should have received a copy of the GNU General Public License
- # along with this program. If not, see <http://www.gnu.org/licenses/>.
- # Global dictionary entry
- NUMERALS = {'I':1,
- 'V':5,
- 'X':10,
- 'L':50,
- 'C':100,
- 'D':500,
- 'M':1000}
- def verify_combo(numeral, first, second):
- """Compares two values for a ratio. The maximal ratio between two numbers in
- the Roman numeral system, it turns out, is 0.1. If this condition is not
- met, throw an exception.
- """
- if first / second >= 0.1:
- pass
- else:
- raise ValueError("{} is not a valid Roman numeral.".format(numeral))
- def is_combo(first, second):
- """In case of Roman numeral combos (e.g., IV), the second value is always
- bigger than the first. This function tests against that.
- """
- if first < second:
- return True
- else:
- return False
- def compare(numeral, index):
- """Compares preceeding, current and succeeding numeral digits.
- Returns current digit if no combo is present.
- Returns combo value of current digit and succeeding digit are a combo.
- Returns 0 if current digit and preceeding digit are a combo.
- """
- # Initialise integer values.
- try:
- previous = NUMERALS[numeral[index-1]]
- current = NUMERALS[numeral[index]]
- next = NUMERALS[numeral[index+1]]
- except IndexError:
- pass
- if index != len(numeral)-1 and is_combo(current, next):
- verify_combo(numeral, current, next)
- return next - current
- elif index > 0 and is_combo(previous, current):
- return 0
- else:
- return current
- def numeral_to_decimal(numeral):
- """Converts a numeral string value to a decimal int value."""
- decimal = 0
- # Loop through every possible letter in the numeral value.
- # Add returned value from compare() to decimal.
- for letter in range(len(numeral)):
- decimal += compare(numeral, letter)
- return decimal
- def decimal_to_numeral(decimal):
- """Converts a decimal int value to a numeral string value."""
- numeral = ""
- numeral_tuples = []
- # Generate a tuple of tuples that is ordered (numeral digit, decimal value).
- for letter in sorted(NUMERALS, key=NUMERALS.get, reverse=True):
- numeral_tuples.append((letter, NUMERALS[letter]))
- # For every possible numeral digit.
- for i in range(len(NUMERALS)):
- # Perform below operations until decimal is smaler than the
- # corresponding value of the letter.
- while decimal >= numeral_tuples[i][1]:
- # The magic happens below. Undocumentable.
- if str(decimal).startswith('9')\
- and str(numeral_tuples[i][1]).startswith('5'):
- break
- elif str(decimal).startswith('4'):
- decimal -= numeral_tuples[i-1][1] * 0.8
- numeral += numeral_tuples[i][0] + numeral_tuples[i-1][0]
- elif str(decimal).startswith('9'):
- decimal -= numeral_tuples[i-2][1] * 0.9
- numeral += numeral_tuples[i][0] + numeral_tuples[i-2][0]
- else:
- decimal -= numeral_tuples[i][1]
- numeral += numeral_tuples[i][0]
- return numeral
- def main():
- # Test results.
- print(numeral_to_decimal("MCMLIV"))
- print()
- print(numeral_to_decimal("MMVIII"))
- print()
- print(numeral_to_decimal("MCMXC"))
- print()
- print(numeral_to_decimal("MCDIV"))
- #print()
- #print(numeral_to_decimal("IM"))
- print()
- print(numeral_to_decimal(decimal_to_numeral(114)))
- print()
- print(decimal_to_numeral(numeral_to_decimal("MCMLIV")))
- print()
- print(decimal_to_numeral(numeral_to_decimal("MMVIII")))
- print()
- print(numeral_to_decimal(decimal_to_numeral(444)))
- if __name__ == "__main__":
- main()
Advertisement
Add Comment
Please, Sign In to add comment