Created
January 15, 2013 23:05
-
-
Save chadbrewbaker/4542999 to your computer and use it in GitHub Desktop.
Iowa Ruby Brigade kata showing Roman numeral computation is a monoid.
This file contains 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
# Roman Numeral Evaluation is a Monoid | |
# Chad Brewbaker | Software Engineer | Telligen.org | |
# [email protected] | |
# 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") |
Look at initialize(). That struct of seven variables is the monoid identity. For complex monoids you have to do a lot of book-keeping variables.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I'm lost, how can roman numbers be a monoid if there's no identity element? There's no 0.