This commit is contained in:
2016-09-12 17:41:46 -05:00
parent 2f99878b09
commit 1415b3ea84
10 changed files with 1190 additions and 1 deletions

View File

@@ -0,0 +1,77 @@
# Kindergarten Garden
Write a program that, given a diagram, can tell you which plants each child in the kindergarten class is responsible for.
The kindergarten class is learning about growing plants. The teachers
thought it would be a good idea to give them actual seeds, plant them in
actual dirt, and grow actual plants.
They've chosen to grow grass, clover, radishes, and violets.
To this end, they've put little styrofoam cups along the window sills,
and planted one type of plant in each cup, choosing randomly from the
available types of seeds.
```plain
[window][window][window]
........................ # each dot represents a styrofoam cup
........................
```
There are 12 children in the class:
- Alice, Bob, Charlie, David,
- Eve, Fred, Ginny, Harriet,
- Ileana, Joseph, Kincaid, and Larry.
Each child gets 4 cups, two on each row. The children are assigned to
cups in alphabetical order.
The following diagram represents Alice's plants:
```plain
[window][window][window]
VR......................
RG......................
```
So in the row nearest the window, she has a violet and a radish; in the
row behind that, she has a radish and some grass.
Your program will be given the plants from left-to-right starting with
the row nearest the windows. From this, it should be able to determine
which plants belong to which students.
For example, if it's told that the garden looks like so:
```plain
[window][window][window]
VRCGVVRVCGGCCGVRGCVCGCGV
VRCCCGCRRGVCGCRVVCVGCGCV
```
Then if asked for Alice's plants, it should provide:
- Violets, radishes, violets, radishes
While asking for Bob's plants would yield:
- Clover, grass, clover, clover
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
Random musings during airplane trip. [http://jumpstartlab.com](http://jumpstartlab.com)
## Submitting Incomplete Problems
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

View File

@@ -0,0 +1,93 @@
package kindergarten
import (
"errors"
"sort"
"strings"
)
type Garden struct {
children []string
rows []string
}
func NewGarden(diagram string, children []string) (*Garden, error) {
var err error
g := new(Garden)
g.rows = strings.Split(diagram[1:], "\n")
g.children = children
if diagram[0] != '\n' {
err = errors.New("Wrong diagram format")
} else if len(g.rows) == 0 {
err = errors.New("No rows")
} else if len(g.children) == 0 {
err = errors.New("No children")
} else if len(g.rows[0]) != len(g.rows[1]) {
err = errors.New("Mismatched rows")
} else {
for i := range g.rows {
if len(g.rows[i])%2 != 0 {
err = errors.New("Odd number of cups")
break
}
for j := range g.rows[i] {
tst := g.rows[i][j]
switch tst {
case 'R':
case 'C':
case 'G':
case 'V':
default:
err = errors.New("Invalid Cup Codes")
}
}
if err != nil {
break
}
}
for i := range g.children {
if i > 0 {
if g.children[i] == g.children[i-1] {
err = errors.New("Duplicate Children")
break
}
}
}
}
return g, err
}
func (g *Garden) Plants(child string) ([]string, bool) {
var i int
var ret []string
var found bool
c := g.children
sort.Strings(c)
for i = 0; i < len(c); i++ {
if c[i] == child {
found = true
break
}
}
if !found || len(g.rows) == 0 || len(g.rows[0]) <= 2*i {
return ret, found
}
for j := range []int{0, 1} {
for k := range []int{0, 1} {
switch g.rows[j][(i*2 + k)] {
case 'G':
ret = append(ret, "grass")
case 'C':
ret = append(ret, "clover")
case 'R':
ret = append(ret, "radishes")
case 'V':
ret = append(ret, "violets")
}
}
}
return ret, found
}
// kindergarten_garden_test.go:140: Garden 6 lookup Patricia =
// [radishes radishes grass clover], want [violets clover radishes violets].

View File

@@ -0,0 +1,211 @@
// Kindergarten garden
//
// You must define a type Garden with constructor
//
// func NewGarden(diagram string, children []string) (*Garden, error)
//
// and method
//
// func (g *Garden) Plants(child string) ([]string, bool)
//
// The diagram argument starts each row with a '\n'. This allows Go's
// raw string literals to present diagrams in source code nicely as two
// rows flush left, for example,
//
// diagram := `
// VVCCGG
// VVCCGG`
package kindergarten
import (
"reflect"
"sort"
"testing"
)
type lookup struct {
child string
plants []string
ok bool
}
type gardenTest struct {
number int
diagram string
children []string
ok bool
lookups []lookup
}
var tests = []gardenTest{
{1, `
RC
GG`, []string{"Alice"}, true, []lookup{
{"Alice", []string{"radishes", "clover", "grass", "grass"}, true},
}},
{2, `
VC
RC`, []string{"Alice"}, true, []lookup{
{"Alice", []string{"violets", "clover", "radishes", "clover"}, true},
}},
{3, `
VVCG
VVRC`, []string{"Alice", "Bob"}, true, []lookup{
{"Bob", []string{"clover", "grass", "radishes", "clover"}, true},
}},
{4, `
VVCCGG
VVCCGG`, []string{"Alice", "Bob", "Charlie"}, true, []lookup{
{"Bob", []string{"clover", "clover", "clover", "clover"}, true},
{"Charlie", []string{"grass", "grass", "grass", "grass"}, true},
}},
test5, // full garden test
test6, // out of order names test
// failure tests
{7, "RC\nGG", []string{"Alice"}, false, nil}, // wrong diagram format
{8, `
RCCC
GG`, []string{""}, false, nil}, // mismatched rows
{9, `
RCC
GGC`, []string{"Alice"}, false, nil}, // odd number of cups
{10, `
RCCC
GGCC`, []string{"Alice", "Alice"}, false, nil}, // duplicate name
{11, `
rc
gg`, []string{"Alice"}, false, nil}, // invaid cup codes
{12, `
RC
GG`, []string{"Alice"}, true, []lookup{ // lookup invalid name
{"Bob", []string{"radishes", "clover", "grass", "grass"}, false},
}},
}
// full garden test
var test5 = gardenTest{5, `
VRCGVVRVCGGCCGVRGCVCGCGV
VRCCCGCRRGVCGCRVVCVGCGCV`, []string{
"Alice", "Bob", "Charlie", "David", "Eve", "Fred",
"Ginny", "Harriet", "Ileana", "Joseph", "Kincaid", "Larry"}, true, []lookup{
{"Alice", []string{"violets", "radishes", "violets", "radishes"}, true},
{"Bob", []string{"clover", "grass", "clover", "clover"}, true},
{"Charlie", []string{"violets", "violets", "clover", "grass"}, true},
{"David", []string{"radishes", "violets", "clover", "radishes"}, true},
{"Eve", []string{"clover", "grass", "radishes", "grass"}, true},
{"Fred", []string{"grass", "clover", "violets", "clover"}, true},
{"Ginny", []string{"clover", "grass", "grass", "clover"}, true},
{"Harriet", []string{"violets", "radishes", "radishes", "violets"}, true},
{"Ileana", []string{"grass", "clover", "violets", "clover"}, true},
{"Joseph", []string{"violets", "clover", "violets", "grass"}, true},
{"Kincaid", []string{"grass", "clover", "clover", "grass"}, true},
{"Larry", []string{"grass", "violets", "clover", "violets"}, true},
}}
// out of order names test
var (
test6names = []string{"Samantha", "Patricia", "Xander", "Roger"}
test6 = gardenTest{6, `
VCRRGVRG
RVGCCGCV`, append([]string{}, test6names...), true, []lookup{
{"Patricia", []string{"violets", "clover", "radishes", "violets"}, true},
{"Roger", []string{"radishes", "radishes", "grass", "clover"}, true},
{"Samantha", []string{"grass", "violets", "clover", "grass"}, true},
{"Xander", []string{"radishes", "grass", "clover", "violets"}, true},
}}
)
func TestGarden(t *testing.T) {
for _, test := range tests {
g, err := NewGarden(test.diagram, test.children)
switch {
case err != nil:
if test.ok {
t.Fatalf("NewGarden test %d returned error %q. Error not expected.",
test.number, err)
}
case !test.ok:
t.Fatalf("NewGarden test %d error = %v. Expected error.",
test.number, err)
}
for _, l := range test.lookups {
switch plants, ok := g.Plants(l.child); {
case ok != l.ok:
t.Fatalf("Garden %d lookup %s returned ok = %t, want %t.",
test.number, l.child, ok, l.ok)
case ok && !reflect.DeepEqual(plants, l.plants):
t.Fatalf("Garden %d lookup %s = %v, want %v.",
test.number, l.child, plants, l.plants)
}
}
}
}
// The lazy way to meet the alphabetizing requirement is with sort.Strings
// on the argument slice. That's an in-place sort though and it's bad practice
// to have a side effect.
func TestNamesNotModified(t *testing.T) {
cp := append([]string{}, test6names...)
_, err := NewGarden(test6.diagram, cp)
if err != nil {
t.Skip("TestNamesNotModified requires valid garden")
}
if !reflect.DeepEqual(cp, test6names) {
t.Fatalf("NewGarden modified children argment. " +
"Arguments should not be modified.")
}
sort.Strings(cp)
if reflect.DeepEqual(cp, test6names) {
t.Skip("TestNamesNotModified requires names out of order")
}
}
// A test taken from the Ruby tests. It checks that Garden objects
// are self-contained and do not rely on package variables.
func TestTwoGardens(t *testing.T) {
diagram := `
VCRRGVRG
RVGCCGCV`
g1, err1 := NewGarden(diagram, []string{"Alice", "Bob", "Charlie", "Dan"})
g2, err2 := NewGarden(diagram, []string{"Bob", "Charlie", "Dan", "Erin"})
if err1 != nil || err2 != nil {
t.Skip("Two garden test needs valid gardens")
}
tf := func(g *Garden, n int, child string, expPlants []string) {
switch plants, ok := g.Plants(child); {
case !ok:
t.Skip("Garden %d lookup %s returned ok = false, want true.",
n, child)
case !reflect.DeepEqual(plants, expPlants):
t.Fatalf("Garden %d lookup %s = %v, want %v.",
n, child, plants, expPlants)
}
}
tf(g1, 1, "Bob", []string{"radishes", "radishes", "grass", "clover"})
tf(g2, 2, "Bob", []string{"violets", "clover", "radishes", "violets"})
tf(g1, 1, "Charlie", []string{"grass", "violets", "clover", "grass"})
tf(g2, 2, "Charlie", []string{"radishes", "radishes", "grass", "clover"})
}
func BenchmarkNewGarden(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, test := range tests {
NewGarden(test.diagram, test.children)
}
}
}
func BenchmarkGarden_Plants(b *testing.B) {
g, err := NewGarden(test5.diagram, test5.children)
if err != nil {
b.Skip("BenchmarkGarden_Plants requires valid garden")
}
b.ResetTimer()
for i := 0; i < b.N; i++ {
for _, l := range test5.lookups {
g.Plants(l.child)
}
}
}