summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2016-08-28 13:04:34 +0200
committerDimitri Sokolyuk <demon@dim13.org>2016-08-28 13:04:34 +0200
commite9fcb7682261fc9cc62e601404f2f6aef94b1962 (patch)
tree879f2e06456a1988e9e0939a1ceaff80167b7e1d
parent6e5c7cbb5923f7627abc3b720600b6f1df718132 (diff)
Solve say
-rw-r--r--go/say/README.md81
-rw-r--r--go/say/say.go74
-rw-r--r--go/say/say_test.go47
3 files changed, 202 insertions, 0 deletions
diff --git a/go/say/README.md b/go/say/README.md
new file mode 100644
index 0000000..426af71
--- /dev/null
+++ b/go/say/README.md
@@ -0,0 +1,81 @@
+# Say
+
+Write a program that will take a number from 0 to 999,999,999,999 and spell out that number in English.
+
+## Step 1
+
+Handle the basic case of 0 through 99.
+
+If the input to the program is `22`, then the output should be
+`'twenty-two'`.
+
+Your program should complain loudly if given a number outside the
+blessed range.
+
+Some good test cases for this program are:
+
+- 0
+- 14
+- 50
+- 98
+- -1
+- 100
+
+### Extension
+
+If you're on a Mac, shell out to Mac OS X's `say` program to talk out
+loud.
+
+## Step 2
+
+Implement breaking a number up into chunks of thousands.
+
+So `1234567890` should yield a list like 1, 234, 567, and 890, while the
+far simpler `1000` should yield just 1 and 0.
+
+The program must also report any values that are out of range.
+
+## Step 3
+
+Now handle inserting the appropriate scale word between those chunks.
+
+So `1234567890` should yield `'1 billion 234 million 567 thousand 890'`
+
+The program must also report any values that are out of range. It's
+fine to stop at "trillion".
+
+## Step 4
+
+Put it all together to get nothing but plain English.
+
+`12345` should give `twelve thousand three hundred forty-five`.
+
+The program must also report any values that are out of range.
+
+### Extensions
+
+Use _and_ (correctly) when spelling out the number in English:
+
+- 14 becomes "fourteen".
+- 100 becomes "one hundred".
+- 120 becomes "one hundred and twenty".
+- 1002 becomes "one thousand and two".
+- 1323 becomes "one thousand three hundred and twenty-three".
+
+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
+
+A variation on JavaRanch CattleDrive, exercise 4a [http://www.javaranch.com/say.jsp](http://www.javaranch.com/say.jsp)
+
+## Submitting Incomplete Problems
+It's possible to submit an incomplete solution so you can see how others have completed the exercise.
+
diff --git a/go/say/say.go b/go/say/say.go
new file mode 100644
index 0000000..4fdc5b4
--- /dev/null
+++ b/go/say/say.go
@@ -0,0 +1,74 @@
+package say
+
+import "strings"
+
+var small = []string{
+ "", "one", "two", "three", "four", "five",
+ "six", "seven", "eight", "nine", "ten",
+ "eleven", "twelve", "thirteen", "fourteen", "fifteen",
+ "sixteen", "seventeen", "eighteen", "nineteen",
+}
+
+var tens = []string{
+ "", "", "twenty", "thirty", "forty", "fifty",
+ "sixty", "seventy", "eighty", "ninety",
+}
+
+var scale = []string{
+ "", "thousand", "million", "billion", "trillion",
+ "quadrillion", "quintillion",
+}
+
+type Group struct {
+ Value uint64
+ Power int
+}
+
+func (g Group) String() string {
+ var s []string
+ if h := g.Value / 100; h > 0 {
+ s = append(s, small[h]+" hundred")
+ }
+ if t := g.Value % 100; t > 0 {
+ if tns := t / 10; tns >= 2 {
+ if sml := t % 10; sml > 0 {
+ s = append(s, tens[tns]+"-"+small[sml])
+ } else {
+ s = append(s, tens[tns])
+ }
+ } else if t > 0 {
+ s = append(s, small[t])
+ }
+ }
+ if p := scale[g.Power]; p != "" && len(s) > 0 {
+ s = append(s, p)
+ }
+ return strings.Join(s, " ")
+}
+
+func split(n uint64) []Group {
+ var g []Group
+ for i := 0; n > 0; i++ {
+ r := n % 1e3
+ n /= 1e3
+ g = append(g, Group{
+ Value: r,
+ Power: i,
+ })
+ }
+ return g
+}
+
+func Say(n uint64) string {
+ if n <= 0 {
+ return "zero"
+ }
+ g := split(n)
+ var s []string
+ for i := len(g) - 1; i >= 0; i-- {
+ if str := g[i].String(); str != "" {
+ s = append(s, str)
+ }
+ }
+ return strings.Join(s, " ")
+}
diff --git a/go/say/say_test.go b/go/say/say_test.go
new file mode 100644
index 0000000..e4144a5
--- /dev/null
+++ b/go/say/say_test.go
@@ -0,0 +1,47 @@
+package say
+
+// The steps are interesting, but all that matters is the final exam.
+
+import (
+ "math"
+ "testing"
+)
+
+var tests = []struct {
+ uint64
+ string
+}{
+ {1, "one"},
+ {14, "fourteen"},
+ {20, "twenty"},
+ {22, "twenty-two"},
+ {100, "one hundred"},
+ {120, "one hundred twenty"},
+ {123, "one hundred twenty-three"},
+ {1000, "one thousand"},
+ {1234, "one thousand two hundred thirty-four"},
+ {1000000, "one million"},
+ {1000002, "one million two"},
+ {1002345, "one million two thousand three hundred forty-five"},
+ {1e9, "one billion"},
+ {987654321123, "nine hundred eighty-seven billion " +
+ "six hundred fifty-four million " +
+ "three hundred twenty-one thousand " +
+ "one hundred twenty-three"},
+ {0, "zero"},
+ {math.MaxUint64, "eighteen quintillion " +
+ "four hundred forty-six quadrillion " +
+ "seven hundred forty-four trillion " +
+ "seventy-three billion " +
+ "seven hundred nine million " +
+ "five hundred fifty-one thousand " +
+ "six hundred fifteen"},
+}
+
+func TestSay(t *testing.T) {
+ for _, test := range tests {
+ if s := Say(test.uint64); s != test.string {
+ t.Errorf("Say(%d) = %q. Want %q.", test.uint64, s, test.string)
+ }
+ }
+}