Skip to content

Instantly share code, notes, and snippets.

@wccrawford
Created July 6, 2010 15:47
Show Gist options
  • Save wccrawford/465548 to your computer and use it in GitHub Desktop.
Save wccrawford/465548 to your computer and use it in GitHub Desktop.
#!/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