using System;
using System.Collections.Generic;
namespace RomanNumerals
{
public static class Program
{
public static void Main()
{
try
{
Dictionary<Char, UInt16> romanNumerals;
String input;
List<UInt16> numbers;
UInt16 highestNumber;
String highestNumeral;
UInt16 result;
UInt16 dCount;
UInt16 cCount;
UInt16 lCount;
UInt16 xCount;
UInt16 vCount;
UInt16 iCount;
romanNumerals = new Dictionary<Char, UInt16>(7);
romanNumerals.Add('I', 1);
romanNumerals.Add('V', 5);
romanNumerals.Add('X', 10);
romanNumerals.Add('L', 50);
romanNumerals.Add('C', 100);
romanNumerals.Add('D', 500);
romanNumerals.Add('M', 1000);
Console.WriteLine("Please enter a roman numeral and press <Enter>");
input = Console.ReadLine().ToUpper();
numbers = new List<UInt16>(input.Length);
#region Input Checking
//The following code check against the following rules:
//The numbers have to be steady or descending
//You can substract C only from M and D
//You can substract X only from C and L
//You can substract I only from X and V
//D, L and V can only appear once
//C, X and I can only appear thrice in a row
highestNumber = 1000;
highestNumeral = "M";
dCount = 0;
cCount = 0;
lCount = 0;
xCount = 0;
vCount = 0;
iCount = 0;
foreach(Char letter in input)
{
UInt16 number;
if(romanNumerals.TryGetValue(letter, out number) == false)
{
Console.WriteLine("'{0}' is not a roman number", letter);
return;
}
numbers.Add(number);
}
for(Int32 i = 0; i < numbers.Count; i++)
{
if(i < numbers.Count - 1)
{
if(numbers[i] < numbers[i + 1])
{
UInt16 substraction;
if(numbers[i] == 1)
{
if((numbers[i + 1] != 5) && (numbers[i + 1] != 10))
{
Console.WriteLine("You can substract 'I' only from 'V' or 'X'");
return;
}
}
else if(numbers[i] == 10)
{
if((numbers[i + 1] != 50) && (numbers[i + 1] != 100))
{
Console.WriteLine("You can substract 'X' only from 'L' or 'C'");
return;
}
}
else if(numbers[i] == 100)
{
if((numbers[i + 1] != 500) && (numbers[i + 1] != 1000))
{
Console.WriteLine("You can substract 'C' only from 'D' or 'M'");
return;
}
}
else
{
Console.WriteLine("You cannot substract '{0}' from '{1}'", input[i], input[i + 1]);
return;
}
substraction = (UInt16)(numbers[i + 1] - numbers[i]);
if(substraction > highestNumber)
{
Console.WriteLine("You cannot have '{0}' following '{1}'", input[i].ToString() + input[i + 1].ToString(), highestNumeral);
return;
}
else
{
highestNumeral = input[i].ToString() + input[i + 1].ToString();
if(substraction == highestNumber)
{
Console.WriteLine("You cannot have '{0}' following '{0}'", highestNumeral);
return;
}
highestNumber = (UInt16)(numbers[i] - 1);
i++;
if(DetermineMaxSequentials(input, numbers, i, ref dCount, ref cCount, ref lCount, ref xCount, ref vCount, ref iCount, true))
{
return;
}
continue;
}
}
}
if(numbers[i] > highestNumber)
{
Console.WriteLine("You cannot have '{0}' following '{1}'", input[i], highestNumeral);
return;
}
else
{
if(DetermineMaxSequentials(input, numbers, i, ref dCount, ref cCount, ref lCount, ref xCount, ref vCount, ref iCount, false))
{
return;
}
highestNumber = numbers[i];
highestNumeral = input[i].ToString();
}
}
#endregion
#region Calculation
result = 0;
for(Int32 i = 0; i < numbers.Count; i++)
{
if(i == numbers.Count - 1)
{
result += numbers[i];
}
else
{
if(numbers[i] < numbers[i + 1])
{
UInt16 substraction;
substraction = (UInt16)(numbers[i + 1] - numbers[i]);
result += substraction;
i++;
}
else
{
result += numbers[i];
}
}
}
#endregion
Console.WriteLine("Result: {0}", result);
}
catch(Exception ex)
{
Console.WriteLine("Exception: {0}", ex.Message);
}
finally
{
Console.WriteLine("Press <Enter> to exit");
Console.ReadLine();
}
}
#region Input Checking
private static Boolean DetermineMaxSequentials(String input
, List<UInt16> numbers
, Int32 index
, ref UInt16 dCount
, ref UInt16 cCount
, ref UInt16 lCount
, ref UInt16 xCount
, ref UInt16 vCount
, ref UInt16 iCount
, Boolean isSubstraction)
{
Boolean abort;
UInt16 maxOne;
UInt16 maxThree;
maxOne = 1;
if(isSubstraction)
{
maxThree = 4;
}
else
{
maxThree = 3;
}
if(DetermineMaxSequentials(input, numbers, index, ref dCount, maxOne, 500, "one", out abort) == false)
{
if(DetermineMaxSequentials(input, numbers, index, ref cCount, maxThree, 100, "three", out abort) == false)
{
if(DetermineMaxSequentials(input, numbers, index, ref lCount, maxOne, 50, "one", out abort) == false)
{
if(DetermineMaxSequentials(input, numbers, index, ref xCount, maxThree, 10, "three", out abort) == false)
{
if(DetermineMaxSequentials(input, numbers, index, ref vCount, maxOne, 5, "one", out abort) == false)
{
DetermineMaxSequentials(input, numbers, index, ref iCount, maxThree, 1, "three", out abort);
}
}
}
}
}
return (abort);
}
private static Boolean DetermineMaxSequentials(String input
, List<UInt16> numbers
, Int32 index
, ref UInt16 count
, UInt16 maxCount
, UInt16 value
, String numberWord
, out Boolean abort)
{
abort = false;
if(numbers[index] == value)
{
count++;
if(count > maxCount)
{
Console.WriteLine("You cannot have more than {0} '{1}'", numberWord, input[index]);
abort = true;
}
return (true);
}
return (false);
}
#endregion
}
}