summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDimitri Sokolyuk <demon@dim13.org>2016-08-28 14:41:56 +0200
committerDimitri Sokolyuk <demon@dim13.org>2016-08-28 14:41:56 +0200
commita9ae4ebc6006271fc0e95626e0c95e6b9cc786de (patch)
treeda95be2382b384b52dd0157c1b6126e9b57b3d4f
parentfef4ced569da1bdbc167d0786ab0a188973de3c5 (diff)
Solve robot
-rw-r--r--go/robot-name/README.md35
-rw-r--r--go/robot-name/bonus_test.go29
-rw-r--r--go/robot-name/robot_name.go33
-rw-r--r--go/robot-name/robot_name_test.go51
4 files changed, 148 insertions, 0 deletions
diff --git a/go/robot-name/README.md b/go/robot-name/README.md
new file mode 100644
index 0000000..5063b90
--- /dev/null
+++ b/go/robot-name/README.md
@@ -0,0 +1,35 @@
+# Robot Name
+
+Write a program that manages robot factory settings.
+
+When robots come off the factory floor, they have no name.
+
+The first time you boot them up, a random name is generated in the format
+of two uppercase letters followed by three digits, such as RX837 or BC811.
+
+Every once in a while we need to reset a robot to its factory settings,
+which means that their name gets wiped. The next time you ask, it will
+respond with a new random name.
+
+The names must be random: they should not follow a predictable sequence.
+Random names means a risk of collisions. Your solution should not allow
+the use of the same name twice when avoidable. In some exercism language
+tracks there are tests to ensure that the same name is never used twice.
+
+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 debugging session with Paul Blackwell at gSchool. [http://gschool.it](http://gschool.it)
+
+## 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/robot-name/bonus_test.go b/go/robot-name/bonus_test.go
new file mode 100644
index 0000000..17e7df9
--- /dev/null
+++ b/go/robot-name/bonus_test.go
@@ -0,0 +1,29 @@
+// +build bonus
+
+package robotname
+
+import "testing"
+
+func TestCollisions(t *testing.T) {
+ m := map[string]bool{}
+ // Test uniqueness for new robots.
+ // 10k should be plenty to catch names generated
+ // randomly without a uniqueness check.
+ for i := 0; i < 10000; i++ {
+ n := New().Name()
+ if m[n] {
+ t.Fatalf("Name %s reissued after %d robots.", n, i)
+ }
+ m[n] = true
+ }
+ // Test that names aren't recycled either.
+ r := New()
+ for i := 0; i < 10000; i++ {
+ r.Reset()
+ n := r.Name()
+ if m[n] {
+ t.Fatalf("Name %s reissued after Reset.", n)
+ }
+ m[n] = true
+ }
+}
diff --git a/go/robot-name/robot_name.go b/go/robot-name/robot_name.go
new file mode 100644
index 0000000..6230e1c
--- /dev/null
+++ b/go/robot-name/robot_name.go
@@ -0,0 +1,33 @@
+package robotname
+
+import (
+ "math/rand"
+ "time"
+)
+
+func init() {
+ rand.Seed(time.Now().UnixNano())
+}
+
+type Robot struct {
+ name string
+}
+
+func randLetter() string { return string('A' + rand.Intn(26)) }
+func randNumber() string { return string('0' + rand.Intn(10)) }
+
+func newName() string {
+ return randLetter() + randLetter() +
+ randNumber() + randNumber() + randNumber()
+}
+
+func (r *Robot) Name() string {
+ if r.name == "" {
+ r.name = newName()
+ }
+ return r.name
+}
+
+func (r *Robot) Reset() {
+ r.name = ""
+}
diff --git a/go/robot-name/robot_name_test.go b/go/robot-name/robot_name_test.go
new file mode 100644
index 0000000..414b0db
--- /dev/null
+++ b/go/robot-name/robot_name_test.go
@@ -0,0 +1,51 @@
+package robotname
+
+import (
+ "regexp"
+ "testing"
+)
+
+func New() *Robot { return new(Robot) }
+
+var namePat = regexp.MustCompile(`^[A-Z]{2}\d{3}$`)
+
+func TestNameValid(t *testing.T) {
+ n := New().Name()
+ if !namePat.MatchString(n) {
+ t.Errorf(`Invalid robot name %q, want form "AA###".`, n)
+ }
+}
+
+func TestNameSticks(t *testing.T) {
+ r := New()
+ n1 := r.Name()
+ n2 := r.Name()
+ if n2 != n1 {
+ t.Errorf(`Robot name changed. Now %s, was %s.`, n2, n1)
+ }
+}
+
+func TestSuccessiveRobotsHaveDifferentNames(t *testing.T) {
+ n1 := New().Name()
+ if New().Name() == n1 {
+ t.Errorf(`Robots with same name. Two %s's.`, n1)
+ }
+}
+
+func TestResetName(t *testing.T) {
+ r := New()
+ n1 := r.Name()
+ r.Reset()
+ if r.Name() == n1 {
+ t.Errorf(`Robot name not cleared on reset. Still %s.`, n1)
+ }
+}
+
+// Note if you go for bonus points, this benchmark likely won't be
+// meaningful. Bonus thought exercise, why won't it be meaningful?
+func BenchmarkName(b *testing.B) {
+ // Benchmark combined time to create robot and name.
+ for i := 0; i < b.N; i++ {
+ New().Name()
+ }
+}