public
Created

Iowa Ruby Brigade kata showing Roman numeral computation is a monoid.

  • Download Gist
Roman.rb
Ruby
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126
# Roman Numeral Evaluation is a Monoid
# Chad Brewbaker | Software Engineer | Telligen.org
# crb002@gmail.com
# Initial release January 15, 2013
 
class RomanMonoid
 
attr_accessor :prefix, :prefix_size, :suffix, :suffix_size, :suffix_credit, :sum, :homo
 
def initialize(val)
#Monoid identity values
@prefix ='I'
@prefix_size = 0
@suffix = 'I'
@suffix_size =0
@suffix_credit =1
@sum = 0
@homo = true
 
if (not (val.nil?))
values = [1, 5, 10, 50, 100, 500, 1000]
indexh = {'I' => 0, 'V'=> 1, 'X'=>2, 'L'=>3, 'C'=>4, 'D'=>5, 'M'=>6}
@prefix=val
@suffix=val
@suffix_credit = 1
@prefix_size=1
@suffix_size=1
@homo = true #When a Roman monoid stops being homogeneous the suffix credit value is known
@sum = values[indexh[val]]
end
 
end
 
def add_right(elt)
values = [1, 5, 10, 50, 100, 500, 1000]
indexh = {'I' => 0, 'V'=> 1, 'X'=>2, 'L'=>3, 'C'=>4, 'D'=>5, 'M'=>6}
same_bonus=0
# Adding a hetero
if elt.homo == false
if(@prefix == elt.suffix)
if elt.suffix_credit < 0
@sum = @sum - (@prefix_size * values[indexh[@prefix]]*2)
end
elsif (indexh[@prefix] < indexh[elt.suffix])
@sum = @sum - (@prefix_size * values[indexh[@prefix]]*2)
if @homo
@suffix_credit = -1
end
end
@homo =false
# Adding a homo
elsif elt.homo == true
if(@prefix == elt.suffix)
same_bonus = @prefix_size
elsif (indexh[@prefix] < indexh[elt.suffix])
@sum = @sum - (@prefix_size * values[indexh[@prefix]]*2)
if(@homo)
@suffix_credit = -1
end
@homo =false
elsif (indexh[@prefix] > indexh[elt.suffix])
@homo =false
end
end
@prefix_size = elt.prefix_size + same_bonus
@sum = @sum + elt.sum
@prefix = elt.prefix
end
end
 
 
def convert_monoid(input)
tmparr = input.chars.to_a
arr = Array.new(input.size) { |i| RomanMonoid.new(tmparr[i]) }
last = RomanMonoid.new(nil)
while (arr.size >0)
v = arr.pop
v.add_right(last)
last = v
end
return last.sum
end
 
def convert_credit(input)
# Rule 1) The last element is always a credit.
# Rule 2) A repeat shares the debit/credit value of it's right neighbor.
# Rule 3) A greater left elt makes this elt a credit.
# Rule 4) A lesser left elt make this elt a debit.
 
values = [1, 5, 10, 50, 100, 500, 1000]
indexh = {'I' => 0, 'V'=> 1, 'X'=>2, 'L'=>3, 'C'=>4, 'D'=>5, 'M'=>6}
arr = input.chars.to_a
 
last_val = 'I'
last_mult = 1
sum = 0
while (arr.size >0)
v = arr.pop
mult = last_mult
if(indexh[v] < indexh[last_val])
mult = -1
end
if(indexh[v] > indexh[last_val])
mult = 1
end
 
sum = sum + (mult* values[indexh[v]])
last_val = v
last_mult = mult
end
 
return sum
end
 
 
puts "Should be 1999"
puts convert_credit("MDCCCCLXXXXVIIII")
puts convert_credit("MCMXCIX")
puts convert_credit("MIM")
puts "-----------------------------------"
puts convert_monoid("MDCCCCLXXXXVIIII")
puts convert_monoid("MCMXCIX")
puts convert_monoid("MIM")

Please sign in to comment on this gist.

Something went wrong with that request. Please try again.