143 lines
No EOL
3.9 KiB
C
Executable file
143 lines
No EOL
3.9 KiB
C
Executable file
/*-----------------------------------------------------------------------------
|
|
* 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);
|
|
} |