Created
July 6, 2010 15:47
-
-
Save wccrawford/465548 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/ruby | |
class RomanNumeral | |
LOOKUP = { | |
:I => 1, | |
:V => 5, | |
:X => 10, | |
:L => 50, | |
:C => 100, | |
:D => 500, | |
:M => 1000, | |
} | |
def RomanNumeral::toInt( numeral ) | |
total = 0 | |
last_value = 1 | |
numeral.reverse.each_char { |x| | |
current_value = RomanNumeral::LOOKUP[x.intern] | |
# Check for the total of that last value and current | |
# value in the list of lookups | |
if(RomanNumeral::LOOKUP.invert[last_value+current_value] != nil) | |
raise Exception, 'Illegal numeral' | |
end | |
# If the last value is larger than the current value | |
# we need to subtract the current value. | |
# Otherwise, we need to add it. | |
if(last_value > current_value) | |
if( (last_value / current_value <=2) or (last_value / current_value > 10) ) | |
raise Exception, "Illegal numeral #{last_value/current_value}" | |
end | |
total -= current_value | |
else | |
total += current_value | |
end | |
last_value = current_value | |
} | |
return total; | |
end | |
def RomanNumeral::toNumeral( integer ) | |
if (integer > 4999) | |
raise Exception, "Number is too large to convert." | |
end | |
values = RomanNumeral::LOOKUP.values.sort.reverse | |
remaining = integer | |
numeral = '' | |
values.each_index { |index| | |
tmpvalue = 0 | |
tmpnumeral = '' | |
x = values[index] | |
# If 2 more values exist, | |
# and this value/next value != 5 | |
# (Because that means number starts with 5) | |
# and this value - 2nd future value is | |
# smaller than the remaining value | |
# and the the current value isn't larger | |
# than the remaining value | |
# Create a subtraction that uses 2 values down. | |
if ( (values[index+2] != nil) and not (values[index]/5 == values[index+1]) and (remaining >= values[index] - values[index+2]) and not ( remaining >= x) ) | |
tmpnumeral = RomanNumeral::LOOKUP.invert[values[index+2]].to_s | |
tmpnumeral << RomanNumeral::LOOKUP.invert[values[index]].to_s | |
tmpvalue = values[index] - values[index+2] | |
# Otherwise, if 1 more values exist, | |
# and this value/next value != 2 | |
# (Because that means number starts with 1) | |
# and this value = next value is smaller | |
# than remaining value | |
# and the current value isn't larger | |
# than the remaining value | |
# Create a substraction that uses the next value | |
elsif ( (values[index+1] != nil) and not (values[index]/values[index+1] == 2) and (remaining >= values[index] - values[index+1]) and not ( remaining >= x) ) | |
tmpnumeral = RomanNumeral::LOOKUP.invert[values[index+1]].to_s | |
tmpnumeral << RomanNumeral::LOOKUP.invert[values[index]].to_s | |
tmpvalue = values[index] - values[index+1] | |
# No need for subtractions, just use the value | |
# if it's bigger. | |
else | |
while(remaining-tmpvalue >= x) | |
tmpnumeral << RomanNumeral::LOOKUP.invert[x].to_s | |
tmpvalue += x | |
end | |
end | |
numeral << tmpnumeral | |
remaining -= tmpvalue | |
} | |
return numeral | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment