Skip to content

Instantly share code, notes, and snippets.

@claudioc
Created December 2, 2012 11:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save claudioc/4188239 to your computer and use it in GitHub Desktop.
Save claudioc/4188239 to your computer and use it in GitHub Desktop.
Roman <=> Integer (Ruby)
module RomanEmpire
emperor = "Claudio Cicali"
@numbers = {
:letters => [ "M", "D", "C", "L", "X", "V", "I" ],
:integers => [ "1000", "500", "100", "50", "10", "5", "1" ]
}
def RomanEmpire.romanFor(integer)
@numbers[:letters][@numbers[:integers].index(integer.to_s)]
end
def RomanEmpire.integerFor(roman)
@numbers[:integers][@numbers[:letters].index(roman)].to_i
end
def RomanEmpire.numbers
@numbers
end
class Number
def initialize(repr)
@value = {
:integer => repr,
:roman => repr
}
# The self test will be removed once we have proper tests
if (repr =~ /\A[+-]?\d+\Z/).nil?
@output_type = :integer
@value[:integer] = parseRoman(repr, 0)
if (parseInteger(@value[:integer]) != @value[:roman])
raise "Duo numeri non equatur! " + (@value[:roman]) + " != " + @value[:integer]
end
else
@output_type = :roman
@value[:roman] = parseInteger(repr);
if (parseRoman(@value[:roman], 0).to_i != @value[:integer].to_i)
raise "Duo numeri non equatur! " + @value[:integer] + " != " + @value[:roman]
end
end
end
def converted
@value[@output_type]
end
private
def parseRoman(roman, acc)
if roman[0].nil?
return acc
end
d0 = RomanEmpire::integerFor(roman[0].chr)
d1 = roman[1].nil? ? 0 : RomanEmpire::integerFor(roman[1].chr)
if d1 <= d0
parseRoman( roman[1..-1], acc + d0 )
elsif d1 > d0
parseRoman( roman[2..-1], acc + ( d1 - d0 ) )
end
end
def parseInteger(integer)
integer = integer.to_s
mult = 0
number = ""
tmp = 0
while integer.length > 0
partial = ""
digit = integer[0].to_i - 48
if digit > 0
mult = 10 ** (integer.length - 1)
tmp = digit * mult
# This is for "special, edge cases".
# Example for "4": mult is 1 and and K esists so that K - 1 = 4. In that case K is 5 so that I use R(1) + R(5) which is IV
# Example for "400": mult is 100 and and K esists so that K - 100 = 400. In that case K is 500 so I use R(100) + R(500) which is CD
RomanEmpire.numbers[:integers].each { | value |
if (value.to_i - tmp ) == mult
partial = (RomanEmpire::romanFor(mult) + RomanEmpire::romanFor(value));
end
}
if (partial == "")
RomanEmpire.numbers[:integers].each { | value |
value = value.to_i
while (tmp - value) >= 0
tmp -= value
partial += RomanEmpire::romanFor(value);
end
}
end
number += partial
end
integer = integer[1..-1]
end
number
end
end
end
ARGF.each_line do |entry|
puts RomanEmpire::Number.new(entry.chop).converted
end
@dboesswetter
Copy link

Hm for me input file, this complains about line 84 (which assumes ASCII input). If you replace it with "integer[0].to_i" it should be more portable (and works for my test files).

@dboesswetter
Copy link

s/me/my/

@claudioc
Copy link
Author

claudioc commented Dec 3, 2012

Oh yeah, I did not any check sorry. Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment