91 lines
1.7 KiB
Go
91 lines
1.7 KiB
Go
|
package main
|
||
|
|
||
|
import "strings"
|
||
|
|
||
|
// ConvertToArabic converts a Roman Numeral to an Arabic number.
|
||
|
func ConvertToArabic(roman string) (total uint16) {
|
||
|
for _, symbols := range windowedRoman(roman).Symbols() {
|
||
|
total += allRomanNumerals.ValueOf(symbols...)
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// ConvertToRoman converts an Arabic number to a Roman Numeral.
|
||
|
func ConvertToRoman(arabic uint16) string {
|
||
|
var result strings.Builder
|
||
|
|
||
|
for _, numeral := range allRomanNumerals {
|
||
|
for arabic >= numeral.Value {
|
||
|
result.WriteString(numeral.Symbol)
|
||
|
arabic -= numeral.Value
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return result.String()
|
||
|
}
|
||
|
|
||
|
type romanNumeral struct {
|
||
|
Value uint16
|
||
|
Symbol string
|
||
|
}
|
||
|
|
||
|
type romanNumerals []romanNumeral
|
||
|
|
||
|
func (r romanNumerals) ValueOf(symbols ...byte) uint16 {
|
||
|
symbol := string(symbols)
|
||
|
for _, s := range r {
|
||
|
if s.Symbol == symbol {
|
||
|
return s.Value
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0
|
||
|
}
|
||
|
|
||
|
func (r romanNumerals) Exists(symbols ...byte) bool {
|
||
|
symbol := string(symbols)
|
||
|
for _, s := range r {
|
||
|
if s.Symbol == symbol {
|
||
|
return true
|
||
|
}
|
||
|
}
|
||
|
return false
|
||
|
}
|
||
|
|
||
|
var allRomanNumerals = romanNumerals{
|
||
|
{1000, "M"},
|
||
|
{900, "CM"},
|
||
|
{500, "D"},
|
||
|
{400, "CD"},
|
||
|
{100, "C"},
|
||
|
{90, "XC"},
|
||
|
{50, "L"},
|
||
|
{40, "XL"},
|
||
|
{10, "X"},
|
||
|
{9, "IX"},
|
||
|
{5, "V"},
|
||
|
{4, "IV"},
|
||
|
{1, "I"},
|
||
|
}
|
||
|
|
||
|
type windowedRoman string
|
||
|
|
||
|
func (w windowedRoman) Symbols() (symbols [][]byte) {
|
||
|
for i := 0; i < len(w); i++ {
|
||
|
symbol := w[i]
|
||
|
notAtEnd := i+1 < len(w)
|
||
|
|
||
|
if notAtEnd && isSubtractive(symbol) && allRomanNumerals.Exists(symbol, w[i+1]) {
|
||
|
symbols = append(symbols, []byte{symbol, w[i+1]})
|
||
|
i++
|
||
|
} else {
|
||
|
symbols = append(symbols, []byte{symbol})
|
||
|
}
|
||
|
}
|
||
|
return
|
||
|
}
|
||
|
|
||
|
func isSubtractive(symbol uint8) bool {
|
||
|
return symbol == 'I' || symbol == 'X' || symbol == 'C'
|
||
|
}
|