Skip to content

Instantly share code, notes, and snippets.

@ooesili
Created April 3, 2015 14:52
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 ooesili/f7da3d1a270758db99d8 to your computer and use it in GitHub Desktop.
Save ooesili/f7da3d1a270758db99d8 to your computer and use it in GitHub Desktop.
Roman Numerals
#!/usr/bin/env ruby
########## GRAB AND VALIDATE INPUT ##########
num_str = STDIN.gets.chomp
if not (1..4999).include? num_str.to_i
warn "number must be between 1 and 4999 (inclusive)"
exit 1
end
########## PAIR UP DIGITS WITH NUMERALS ##########
# digits from the input, as numbers, lowest value first
digits = num_str.each_char.map(&:to_i).reverse
# each digit can be resolved independantly, given the ones, fives, and tens
# numerals for that digit's place
numerals = [
['I', 'V', 'X'],
['X', 'L', 'C'],
['C', 'D', 'M'],
['M', '', '']
]
########## MAIN ALGORITHM ##########
# pair each digit with the numerals need to resolve it
result = digits.zip(numerals).reduce('') do |result, (digit, (one, five, ten))|
# 0..4 is nothing, 4..8 is the fives numeral, 9 is the tens numeral
bases = ['', five, ten]
base = bases[(digit+1) / 5]
# avoid adding nil to strings
# pre and post will both be blank if mod_five is 0
pre = post = ''
# we use `digit % 5` in a few places, so let's calculate it once
mod_five = digit % 5
if mod_five == 4
# prepend a ones numeral for 4 and 9
pre = one
elsif mod_five > 0 or one == 'M'
# this will match 1..3, or anything if we're on the thousands place
# we need this special case to get 'MMMM'
post = one * mod_five
end
# prepend to the result since this loop starts with the lowest value first
pre + base + post + result
end
########## PRINT THE RESULT ##########
puts result
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment