/*----------------------------------------------------------------------------- * HTBLA-Leonding *----------------------------------------------------------------------------- * Author(s): Marc Tismonar *----------------------------------------------------------------------------- * Description: * Encapsulates roman numbers and provides basic mathematical operations. *----------------------------------------------------------------------------- */ #include "roman_number.h" // the maximum number of RomanNumbers #define MAX_ROMAN_NUMBER_COUNT 32 struct RomanNumberData { char* number; int length; }; static RomanNumber romanNumber = {0}; /* Determines whether or not the letter followed by next_letter is a valid subtraction pattern of roman numbers */ static bool rn_is_valid_subtraction(char letter, char next_letter) { return (letter == 'I' && (next_letter == 'V' || next_letter == 'X' || next_letter == 'L' || next_letter == 'C' || next_letter == 'D' || next_letter == 'M')) || (letter == 'X' && (next_letter == 'L' || next_letter == 'C' || next_letter == 'D' || next_letter == 'M')) || (letter == 'C' && (next_letter == 'D' || next_letter == 'M')); } static int roman_char_to_int(char romanNumber) { const char symbols[] = "IVXLCDM"; const int values[] = {1, 5, 10, 50, 100, 500, 1000}; for(int i = 0; i < 7; i++) { if(romanNumber == symbols[i]) return values[i]; } return 0; } static char* int_to_roman(int number) { if (number <= 0) { return ""; } char* result = (char*)calloc(MAX_ROMAN_NUMBER_COUNT, sizeof(char)); const int values[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; const char* numerals[] = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; for (int i = 0; i < 13; i++) { while (number >= values[i]) { strcat(result, numerals[i]); number -= values[i]; } } return result; } RomanNumber rn_create(char* value) { if(value == 0) { return 0; } romanNumber = (RomanNumber)calloc(1, sizeof(struct RomanNumberData)); romanNumber->number = value; romanNumber->length = strlen(value); return romanNumber; } int rn_get_value(RomanNumber number) { if(number == 0 || !rn_is_valid(number)) { return -1; } int next_number = 0; int current_number = 0; int total_number = 0; for(int i = 0; i < strlen(number->number); i++) { current_number = roman_char_to_int(number->number[i]); if (number->number[i+1] == '\0') { total_number += current_number; return total_number; } next_number = roman_char_to_int(number->number[i+1]); if(current_number < next_number) { if(!rn_is_valid_subtraction(number->number[i], number->number[i+1])) { return -1; } total_number -= current_number; } else { total_number += current_number; } } return total_number; } bool rn_is_valid(RomanNumber number) { if(number == 0) { return 0; } for(int i = 0; i < number->length; i++) { if(roman_char_to_int(number->number[i]) == 0) { return false; } } return true; } RomanNumber rn_gcd(RomanNumber x, RomanNumber y) { if(x == 0 || y == 0) { return 0; } int intX = rn_get_value(x); int intY = rn_get_value(y); if (intX < 0 || intY < 0) { return 0; } int result = int_gcd(intX, intY); char* roman_result = int_to_roman(result); return rn_create(roman_result); } int int_gcd(int x, int y) { if(y == 0) { return x; } return int_gcd(y, x % y); }