Update
This commit is contained in:
75
go/diamond/README.md
Normal file
75
go/diamond/README.md
Normal file
@@ -0,0 +1,75 @@
|
||||
# Diamond
|
||||
|
||||
Given a letter, print a diamond starting with 'A' with the supplied letter at the widest point.
|
||||
|
||||
## Diamond kata
|
||||
|
||||
The diamond kata takes as its input a letter, and outputs it in a diamond
|
||||
shape. Given a letter, it prints a diamond starting with 'A', with the
|
||||
supplied letter at the widest point.
|
||||
|
||||
## Requirements
|
||||
|
||||
* The first row contains one 'A'.
|
||||
* The last row contains one 'A'.
|
||||
* All rows, except the first and last, have exactly two identical letters.
|
||||
* All rows have as many trailing spaces as leading spaces. (This might be 0).
|
||||
* The diamond is horizontally symmetric.
|
||||
* The diamond is vertically symmetric.
|
||||
* The diamond has a square shape (width equals height).
|
||||
* The letters form a diamond shape.
|
||||
* The top half has the letters in ascending order.
|
||||
* The bottom half has the letters in descending order.
|
||||
* The four corners (containing the spaces) are triangles.
|
||||
|
||||
## Examples
|
||||
|
||||
In the following examples, spaces are indicated by `·` characters.
|
||||
|
||||
Diamond for letter 'A':
|
||||
|
||||
```plain
|
||||
A
|
||||
```
|
||||
|
||||
Diamond for letter 'C':
|
||||
|
||||
```plain
|
||||
··A··
|
||||
·B·B·
|
||||
C···C
|
||||
·B·B·
|
||||
··A··
|
||||
```
|
||||
|
||||
Diamond for letter 'E':
|
||||
|
||||
```plain
|
||||
····A····
|
||||
···B·B···
|
||||
··C···C··
|
||||
·D·····D·
|
||||
E·······E
|
||||
·D·····D·
|
||||
··C···C··
|
||||
···B·B···
|
||||
····A····
|
||||
```
|
||||
|
||||
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
|
||||
|
||||
Seb Rose [http://claysnow.co.uk/recycling-tests-in-tdd/](http://claysnow.co.uk/recycling-tests-in-tdd/)
|
||||
|
||||
## Submitting Incomplete Problems
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
36
go/diamond/diamond.go
Normal file
36
go/diamond/diamond.go
Normal file
@@ -0,0 +1,36 @@
|
||||
package diamond
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const testVersion = 1
|
||||
|
||||
func Gen(c byte) (string, error) {
|
||||
if c > 'Z' || c < 'A' {
|
||||
return "", errors.New("Out of Range")
|
||||
}
|
||||
d := rune(strings.ToUpper(string(c))[0])
|
||||
|
||||
var ret string
|
||||
for i := 'A'; i <= d; i++ {
|
||||
ret += PrintRow(i, d) + "\n"
|
||||
}
|
||||
for i := d - 1; i >= 'A'; i-- {
|
||||
ret += PrintRow(i, d) + "\n"
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func PrintRow(rowChar rune, genChar rune) string {
|
||||
var ret string
|
||||
ret += strings.Repeat(" ", int(genChar-rowChar))
|
||||
ret += string(rowChar)
|
||||
if rowChar > 'A' {
|
||||
ret += strings.Repeat(" ", (2*int(rowChar-'A') - 1))
|
||||
ret += string(rowChar)
|
||||
}
|
||||
ret += strings.Repeat(" ", int(genChar-rowChar))
|
||||
return ret
|
||||
}
|
227
go/diamond/diamond_test.go
Normal file
227
go/diamond/diamond_test.go
Normal file
@@ -0,0 +1,227 @@
|
||||
package diamond
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
"testing/quick"
|
||||
"time"
|
||||
)
|
||||
|
||||
var config = &quick.Config{Rand: rand.New(rand.NewSource(time.Now().UnixNano()))}
|
||||
|
||||
type correctChar byte
|
||||
|
||||
func (c correctChar) Generate(rand *rand.Rand, _ int) reflect.Value {
|
||||
return reflect.ValueOf(correctChar('A' + rand.Intn('Z'-'A'+1)))
|
||||
}
|
||||
|
||||
func checkCorrect(requirement func(byte, []string) bool, keepSeparator bool, t *testing.T) {
|
||||
assertion := func(char correctChar) bool {
|
||||
d, err := Gen(byte(char))
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
separator := strings.Split
|
||||
if keepSeparator {
|
||||
separator = strings.SplitAfter
|
||||
}
|
||||
rows := separator(d, "\n")
|
||||
if len(rows) < 2 {
|
||||
return false
|
||||
}
|
||||
return requirement(byte(char), rows[:len(rows)-1])
|
||||
}
|
||||
if err := quick.Check(assertion, config); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestFirstRowContainsOneA(t *testing.T) {
|
||||
requirement := func(char byte, rows []string) bool {
|
||||
return len(rows) > 0 && strings.Count(rows[0], "A") == 1
|
||||
}
|
||||
checkCorrect(requirement, false, t)
|
||||
}
|
||||
|
||||
func TestLastRowContainsOneA(t *testing.T) {
|
||||
requirement := func(char byte, rows []string) bool {
|
||||
return len(rows) > 0 && strings.Count(rows[len(rows)-1], "A") == 1
|
||||
}
|
||||
checkCorrect(requirement, false, t)
|
||||
}
|
||||
|
||||
func TestAllRowsIdenticalLettersExceptFirstAndLast(t *testing.T) {
|
||||
requirement := func(char byte, rows []string) bool {
|
||||
for i, row := range rows {
|
||||
r := strings.TrimSpace(row)
|
||||
if r[0] != r[len(r)-1] {
|
||||
return false
|
||||
}
|
||||
if len(r) < 2 && i != 0 && i != len(rows)-1 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
checkCorrect(requirement, false, t)
|
||||
}
|
||||
|
||||
func TestAllRowsHaveSameTrailingSpaces(t *testing.T) {
|
||||
requirement := func(char byte, rows []string) bool {
|
||||
for _, row := range rows {
|
||||
if len(row) == 0 {
|
||||
return false
|
||||
}
|
||||
for i, j := 0, len(row)-1; i < j && row[i] == ' '; i, j = i+1, j-1 {
|
||||
if row[j] != ' ' {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
checkCorrect(requirement, false, t)
|
||||
}
|
||||
|
||||
func TestDiamondIsHorizontallySymmetric(t *testing.T) {
|
||||
requirement := func(char byte, rows []string) bool {
|
||||
for _, row := range rows {
|
||||
l := len(row)
|
||||
for i := l/2 - 1; i >= 0; i-- {
|
||||
if row[i] != row[l-1-i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
checkCorrect(requirement, false, t)
|
||||
}
|
||||
|
||||
func TestDiamondIsVerticallySymmetric(t *testing.T) {
|
||||
requirement := func(char byte, rows []string) bool {
|
||||
for i, j := 0, len(rows)-1; i < j; i, j = i+1, j-1 {
|
||||
if rows[i] != rows[j] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
checkCorrect(requirement, true, t)
|
||||
}
|
||||
|
||||
func TestDiamondIsSquare(t *testing.T) {
|
||||
requirement := func(char byte, rows []string) bool {
|
||||
if int(char-'A')*2+1 != len(rows) {
|
||||
return false
|
||||
}
|
||||
for _, row := range rows {
|
||||
if len(row) != len(rows) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
checkCorrect(requirement, false, t)
|
||||
}
|
||||
|
||||
func TestDiamondHasItsShape(t *testing.T) {
|
||||
requirement := func(char byte, rows []string) bool {
|
||||
var n int
|
||||
for i, row := range rows {
|
||||
s := len(strings.TrimSpace(row))
|
||||
if i > len(rows)/2 && n <= s {
|
||||
return false
|
||||
} else if i <= len(rows)/2 && n >= s {
|
||||
return false
|
||||
}
|
||||
n = s
|
||||
}
|
||||
return true
|
||||
}
|
||||
checkCorrect(requirement, false, t)
|
||||
}
|
||||
|
||||
func TestTopHalfHasAscendingLetters(t *testing.T) {
|
||||
requirement := func(char byte, rows []string) bool {
|
||||
var start byte = 'A' - 1
|
||||
for i := 0; i <= len(rows)/2; i++ {
|
||||
s := strings.TrimLeft(rows[i], " ")
|
||||
if s == "" || s[0] <= start {
|
||||
return false
|
||||
}
|
||||
start = s[0]
|
||||
}
|
||||
return true
|
||||
}
|
||||
checkCorrect(requirement, false, t)
|
||||
}
|
||||
|
||||
func TestBottomHalfHasDescendingLetters(t *testing.T) {
|
||||
requirement := func(char byte, rows []string) bool {
|
||||
var start byte = 'A' - 1
|
||||
for i := len(rows) - 1; i > len(rows)/2; i-- {
|
||||
s := strings.TrimLeft(rows[i], " ")
|
||||
if s == "" || s[0] <= start {
|
||||
return false
|
||||
}
|
||||
start = s[0]
|
||||
}
|
||||
return true
|
||||
}
|
||||
checkCorrect(requirement, false, t)
|
||||
}
|
||||
|
||||
func TestDiamondFourCornersAreTriangle(t *testing.T) {
|
||||
requirement := func(char byte, rows []string) bool {
|
||||
notSpace := func(r rune) bool { return r <= 'Z' && r >= 'A' }
|
||||
var n int
|
||||
for i, row := range rows {
|
||||
s := strings.IndexFunc(row, notSpace)
|
||||
e := len(row) - strings.LastIndexFunc(row, notSpace) - 1
|
||||
if s != e {
|
||||
return false
|
||||
} else if i == 0 {
|
||||
n = s
|
||||
} else {
|
||||
if i > len(rows)/2 && n >= s {
|
||||
return false
|
||||
} else if i <= len(rows)/2 && n <= s {
|
||||
return false
|
||||
}
|
||||
n = s
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
checkCorrect(requirement, false, t)
|
||||
}
|
||||
|
||||
type wrongChar byte
|
||||
|
||||
func (c wrongChar) Generate(rand *rand.Rand, _ int) reflect.Value {
|
||||
b := rand.Intn(256)
|
||||
for ; b >= 'A' && b <= 'Z'; b = rand.Intn(256) {
|
||||
}
|
||||
return reflect.ValueOf(wrongChar(b))
|
||||
}
|
||||
|
||||
func TestCharOutOfRangeShouldGiveError(t *testing.T) {
|
||||
assertion := func(char wrongChar) bool {
|
||||
_, err := Gen(byte(char))
|
||||
return err != nil
|
||||
}
|
||||
if err := quick.Check(assertion, config); err != nil {
|
||||
t.Error(err)
|
||||
}
|
||||
}
|
||||
|
||||
const targetTestVersion = 1
|
||||
|
||||
func TestTestVersion(t *testing.T) {
|
||||
if testVersion != targetTestVersion {
|
||||
t.Errorf("Found testVersion = %v, want %v.", testVersion, targetTestVersion)
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user