Initial Commit
This commit is contained in:
57
go/roman-numerals/README.md
Normal file
57
go/roman-numerals/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Roman Numerals
|
||||
|
||||
Write a function to convert from normal numbers to Roman Numerals: e.g.
|
||||
|
||||
The Romans were a clever bunch. They conquered most of Europe and ruled
|
||||
it for hundreds of years. They invented concrete and straight roads and
|
||||
even bikinis. One thing they never discovered though was the number
|
||||
zero. This made writing and dating extensive histories of their exploits
|
||||
slightly more challenging, but the system of numbers they came up with
|
||||
is still in use today. For example the BBC uses Roman numerals to date
|
||||
their programmes.
|
||||
|
||||
The Romans wrote numbers using letters - I, V, X, L, C, D, M. (notice
|
||||
these letters have lots of straight lines and are hence easy to hack
|
||||
into stone tablets).
|
||||
|
||||
```
|
||||
1 => I
|
||||
10 => X
|
||||
7 => VII
|
||||
```
|
||||
|
||||
There is no need to be able to convert numbers larger than about 3000.
|
||||
(The Romans themselves didn't tend to go any higher)
|
||||
|
||||
Wikipedia says: Modern Roman numerals ... are written by expressing each
|
||||
digit separately starting with the left most digit and skipping any
|
||||
digit with a value of zero.
|
||||
|
||||
To see this in practice, consider the example of 1990.
|
||||
|
||||
In Roman numerals 1990 is MCMXC:
|
||||
|
||||
1000=M
|
||||
900=CM
|
||||
90=XC
|
||||
|
||||
2008 is written as MMVIII:
|
||||
|
||||
2000=MM
|
||||
8=VIII
|
||||
|
||||
See also: http://www.novaroma.org/via_romana/numbers.html
|
||||
|
||||
To run the tests simply run the command `go test` in the exercise directory.
|
||||
|
||||
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||
flag:
|
||||
|
||||
go test -bench .
|
||||
|
||||
For more detailed info about the Go track see the [help
|
||||
page](http://exercism.io/languages/go).
|
||||
|
||||
## Source
|
||||
|
||||
The Roman Numeral Kata [view source](http://codingdojo.org/cgi-bin/wiki.pl?KataRomanNumerals)
|
31
go/roman-numerals/cases_test.go
Normal file
31
go/roman-numerals/cases_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package romannumerals
|
||||
|
||||
// Source: exercism/x-common
|
||||
// Commit: 6985644 Merge pull request #121 from mikeyjcat/add-roman-numerals-test-definition
|
||||
|
||||
type romanNumeralTest struct {
|
||||
arabic int
|
||||
roman string
|
||||
hasError bool
|
||||
}
|
||||
|
||||
var romanNumeralTests = []romanNumeralTest{
|
||||
{1, "I", false},
|
||||
{2, "II", false},
|
||||
{3, "III", false},
|
||||
{4, "IV", false},
|
||||
{5, "V", false},
|
||||
{6, "VI", false},
|
||||
{9, "IX", false},
|
||||
{27, "XXVII", false},
|
||||
{48, "XLVIII", false},
|
||||
{59, "LIX", false},
|
||||
{93, "XCIII", false},
|
||||
{141, "CXLI", false},
|
||||
{163, "CLXIII", false},
|
||||
{402, "CDII", false},
|
||||
{575, "DLXXV", false},
|
||||
{911, "CMXI", false},
|
||||
{1024, "MXXIV", false},
|
||||
{3000, "MMM", false},
|
||||
}
|
BIN
go/roman-numerals/cmd/cmd
Executable file
BIN
go/roman-numerals/cmd/cmd
Executable file
Binary file not shown.
22
go/roman-numerals/cmd/test.go
Normal file
22
go/roman-numerals/cmd/test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"../../roman-numerals"
|
||||
)
|
||||
|
||||
func main() {
|
||||
arabic := []int{0, -1, 4000, 3999, 1, 2, 3, 4, 5, 6, 9, 27, 48, 59, 93, 141, 163, 402, 575, 911, 1024, 3000}
|
||||
for i := range arabic {
|
||||
fmt.Println(strconv.Itoa(arabic[i]) + ": ")
|
||||
if v, err := romannumerals.ToRomanNumeral(arabic[i]); err == nil {
|
||||
fmt.Print("-->")
|
||||
fmt.Println(v)
|
||||
} else {
|
||||
fmt.Print("-->")
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
39
go/roman-numerals/roman_numerals_test.go
Normal file
39
go/roman-numerals/roman_numerals_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package romannumerals
|
||||
|
||||
import "testing"
|
||||
|
||||
const testVersion = 1
|
||||
|
||||
func TestRomanNumerals(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion)
|
||||
}
|
||||
tc := append(romanNumeralTests, []romanNumeralTest{
|
||||
{0, "", true},
|
||||
{-1, "", true},
|
||||
{4000, "", true},
|
||||
{3999, "MMMCMXCIX", false},
|
||||
}...)
|
||||
for _, test := range tc {
|
||||
actual, err := ToRomanNumeral(test.arabic)
|
||||
if err == nil && test.hasError {
|
||||
t.Errorf("ToRomanNumeral(%d) should return an error.", test.arabic)
|
||||
continue
|
||||
}
|
||||
if err != nil && !test.hasError {
|
||||
t.Errorf("ToRomanNumeral(%d) should not return an error.", test.arabic)
|
||||
continue
|
||||
}
|
||||
if actual != test.roman {
|
||||
t.Errorf("ToRomanNumeral(%d): %s, expected %s", test.arabic, actual, test.roman)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRomanNumerals(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range romanNumeralTests {
|
||||
ToRomanNumeral(test.arabic)
|
||||
}
|
||||
}
|
||||
}
|
72
go/roman-numerals/romannumerals.go
Normal file
72
go/roman-numerals/romannumerals.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package romannumerals
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TestVersion tells exercism which tests to use
|
||||
const TestVersion = 1
|
||||
|
||||
// ToRomanNumeral takes an int and returns it's roman numberal string value
|
||||
// Or an error if it can't be done.
|
||||
func ToRomanNumeral(arabic int) (string, error) {
|
||||
if arabic <= 0 || arabic > 3999 {
|
||||
return "", errors.New("Invalid number given")
|
||||
}
|
||||
var ret string
|
||||
var err error
|
||||
var care int
|
||||
place := 1
|
||||
for ; arabic > 0; arabic = (arabic - care) / 10 {
|
||||
care = arabic % 10
|
||||
ret = getRomanChar(care, place) + ret
|
||||
place *= 10
|
||||
}
|
||||
if strings.Contains(ret, "?") {
|
||||
err = errors.New("Invalid number given")
|
||||
}
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func getRomanChar(dg, pl int) string {
|
||||
switch {
|
||||
case dg <= 0:
|
||||
return ""
|
||||
case dg < 4:
|
||||
return strings.Repeat(getOnesPlaceChar(pl), dg)
|
||||
case dg == 4:
|
||||
return getOnesPlaceChar(pl) + getFivesPlaceChar(pl)
|
||||
case dg < 9:
|
||||
return getFivesPlaceChar(pl) + getRomanChar(dg-5, pl)
|
||||
case dg == 9:
|
||||
return getOnesPlaceChar(pl) + getOnesPlaceChar(pl*10)
|
||||
}
|
||||
return "?"
|
||||
}
|
||||
|
||||
func getOnesPlaceChar(pl int) string {
|
||||
switch pl {
|
||||
case 1:
|
||||
return "I"
|
||||
case 10:
|
||||
return "X"
|
||||
case 100:
|
||||
return "C"
|
||||
case 1000:
|
||||
return "M"
|
||||
}
|
||||
return "?"
|
||||
}
|
||||
|
||||
func getFivesPlaceChar(pl int) string {
|
||||
switch pl {
|
||||
case 1:
|
||||
return "V"
|
||||
case 10:
|
||||
return "L"
|
||||
case 100:
|
||||
return "D"
|
||||
}
|
||||
return "?"
|
||||
}
|
Reference in New Issue
Block a user