From a9ae4ebc6006271fc0e95626e0c95e6b9cc786de Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Sun, 28 Aug 2016 14:41:56 +0200 Subject: Solve robot --- go/robot-name/README.md | 35 +++++++++++++++++++++++++++ go/robot-name/bonus_test.go | 29 +++++++++++++++++++++++ go/robot-name/robot_name.go | 33 ++++++++++++++++++++++++++ go/robot-name/robot_name_test.go | 51 ++++++++++++++++++++++++++++++++++++++++ 4 files changed, 148 insertions(+) create mode 100644 go/robot-name/README.md create mode 100644 go/robot-name/bonus_test.go create mode 100644 go/robot-name/robot_name.go create mode 100644 go/robot-name/robot_name_test.go 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() + } +} -- cgit v1.2.3