Updating all of the new ones that are done.
This commit is contained in:
parent
36dc090a89
commit
ec45e6b2eb
339
go/beer-song/README.md
Normal file
339
go/beer-song/README.md
Normal file
@ -0,0 +1,339 @@
|
|||||||
|
# Beer Song
|
||||||
|
|
||||||
|
Write a program which produces the lyrics to that beloved classic, that field-trip favorite: 99 Bottles of Beer on the Wall.
|
||||||
|
|
||||||
|
Note that not all verses are identical.
|
||||||
|
|
||||||
|
```plain
|
||||||
|
99 bottles of beer on the wall, 99 bottles of beer.
|
||||||
|
Take one down and pass it around, 98 bottles of beer on the wall.
|
||||||
|
|
||||||
|
98 bottles of beer on the wall, 98 bottles of beer.
|
||||||
|
Take one down and pass it around, 97 bottles of beer on the wall.
|
||||||
|
|
||||||
|
97 bottles of beer on the wall, 97 bottles of beer.
|
||||||
|
Take one down and pass it around, 96 bottles of beer on the wall.
|
||||||
|
|
||||||
|
96 bottles of beer on the wall, 96 bottles of beer.
|
||||||
|
Take one down and pass it around, 95 bottles of beer on the wall.
|
||||||
|
|
||||||
|
95 bottles of beer on the wall, 95 bottles of beer.
|
||||||
|
Take one down and pass it around, 94 bottles of beer on the wall.
|
||||||
|
|
||||||
|
94 bottles of beer on the wall, 94 bottles of beer.
|
||||||
|
Take one down and pass it around, 93 bottles of beer on the wall.
|
||||||
|
|
||||||
|
93 bottles of beer on the wall, 93 bottles of beer.
|
||||||
|
Take one down and pass it around, 92 bottles of beer on the wall.
|
||||||
|
|
||||||
|
92 bottles of beer on the wall, 92 bottles of beer.
|
||||||
|
Take one down and pass it around, 91 bottles of beer on the wall.
|
||||||
|
|
||||||
|
91 bottles of beer on the wall, 91 bottles of beer.
|
||||||
|
Take one down and pass it around, 90 bottles of beer on the wall.
|
||||||
|
|
||||||
|
90 bottles of beer on the wall, 90 bottles of beer.
|
||||||
|
Take one down and pass it around, 89 bottles of beer on the wall.
|
||||||
|
|
||||||
|
89 bottles of beer on the wall, 89 bottles of beer.
|
||||||
|
Take one down and pass it around, 88 bottles of beer on the wall.
|
||||||
|
|
||||||
|
88 bottles of beer on the wall, 88 bottles of beer.
|
||||||
|
Take one down and pass it around, 87 bottles of beer on the wall.
|
||||||
|
|
||||||
|
87 bottles of beer on the wall, 87 bottles of beer.
|
||||||
|
Take one down and pass it around, 86 bottles of beer on the wall.
|
||||||
|
|
||||||
|
86 bottles of beer on the wall, 86 bottles of beer.
|
||||||
|
Take one down and pass it around, 85 bottles of beer on the wall.
|
||||||
|
|
||||||
|
85 bottles of beer on the wall, 85 bottles of beer.
|
||||||
|
Take one down and pass it around, 84 bottles of beer on the wall.
|
||||||
|
|
||||||
|
84 bottles of beer on the wall, 84 bottles of beer.
|
||||||
|
Take one down and pass it around, 83 bottles of beer on the wall.
|
||||||
|
|
||||||
|
83 bottles of beer on the wall, 83 bottles of beer.
|
||||||
|
Take one down and pass it around, 82 bottles of beer on the wall.
|
||||||
|
|
||||||
|
82 bottles of beer on the wall, 82 bottles of beer.
|
||||||
|
Take one down and pass it around, 81 bottles of beer on the wall.
|
||||||
|
|
||||||
|
81 bottles of beer on the wall, 81 bottles of beer.
|
||||||
|
Take one down and pass it around, 80 bottles of beer on the wall.
|
||||||
|
|
||||||
|
80 bottles of beer on the wall, 80 bottles of beer.
|
||||||
|
Take one down and pass it around, 79 bottles of beer on the wall.
|
||||||
|
|
||||||
|
79 bottles of beer on the wall, 79 bottles of beer.
|
||||||
|
Take one down and pass it around, 78 bottles of beer on the wall.
|
||||||
|
|
||||||
|
78 bottles of beer on the wall, 78 bottles of beer.
|
||||||
|
Take one down and pass it around, 77 bottles of beer on the wall.
|
||||||
|
|
||||||
|
77 bottles of beer on the wall, 77 bottles of beer.
|
||||||
|
Take one down and pass it around, 76 bottles of beer on the wall.
|
||||||
|
|
||||||
|
76 bottles of beer on the wall, 76 bottles of beer.
|
||||||
|
Take one down and pass it around, 75 bottles of beer on the wall.
|
||||||
|
|
||||||
|
75 bottles of beer on the wall, 75 bottles of beer.
|
||||||
|
Take one down and pass it around, 74 bottles of beer on the wall.
|
||||||
|
|
||||||
|
74 bottles of beer on the wall, 74 bottles of beer.
|
||||||
|
Take one down and pass it around, 73 bottles of beer on the wall.
|
||||||
|
|
||||||
|
73 bottles of beer on the wall, 73 bottles of beer.
|
||||||
|
Take one down and pass it around, 72 bottles of beer on the wall.
|
||||||
|
|
||||||
|
72 bottles of beer on the wall, 72 bottles of beer.
|
||||||
|
Take one down and pass it around, 71 bottles of beer on the wall.
|
||||||
|
|
||||||
|
71 bottles of beer on the wall, 71 bottles of beer.
|
||||||
|
Take one down and pass it around, 70 bottles of beer on the wall.
|
||||||
|
|
||||||
|
70 bottles of beer on the wall, 70 bottles of beer.
|
||||||
|
Take one down and pass it around, 69 bottles of beer on the wall.
|
||||||
|
|
||||||
|
69 bottles of beer on the wall, 69 bottles of beer.
|
||||||
|
Take one down and pass it around, 68 bottles of beer on the wall.
|
||||||
|
|
||||||
|
68 bottles of beer on the wall, 68 bottles of beer.
|
||||||
|
Take one down and pass it around, 67 bottles of beer on the wall.
|
||||||
|
|
||||||
|
67 bottles of beer on the wall, 67 bottles of beer.
|
||||||
|
Take one down and pass it around, 66 bottles of beer on the wall.
|
||||||
|
|
||||||
|
66 bottles of beer on the wall, 66 bottles of beer.
|
||||||
|
Take one down and pass it around, 65 bottles of beer on the wall.
|
||||||
|
|
||||||
|
65 bottles of beer on the wall, 65 bottles of beer.
|
||||||
|
Take one down and pass it around, 64 bottles of beer on the wall.
|
||||||
|
|
||||||
|
64 bottles of beer on the wall, 64 bottles of beer.
|
||||||
|
Take one down and pass it around, 63 bottles of beer on the wall.
|
||||||
|
|
||||||
|
63 bottles of beer on the wall, 63 bottles of beer.
|
||||||
|
Take one down and pass it around, 62 bottles of beer on the wall.
|
||||||
|
|
||||||
|
62 bottles of beer on the wall, 62 bottles of beer.
|
||||||
|
Take one down and pass it around, 61 bottles of beer on the wall.
|
||||||
|
|
||||||
|
61 bottles of beer on the wall, 61 bottles of beer.
|
||||||
|
Take one down and pass it around, 60 bottles of beer on the wall.
|
||||||
|
|
||||||
|
60 bottles of beer on the wall, 60 bottles of beer.
|
||||||
|
Take one down and pass it around, 59 bottles of beer on the wall.
|
||||||
|
|
||||||
|
59 bottles of beer on the wall, 59 bottles of beer.
|
||||||
|
Take one down and pass it around, 58 bottles of beer on the wall.
|
||||||
|
|
||||||
|
58 bottles of beer on the wall, 58 bottles of beer.
|
||||||
|
Take one down and pass it around, 57 bottles of beer on the wall.
|
||||||
|
|
||||||
|
57 bottles of beer on the wall, 57 bottles of beer.
|
||||||
|
Take one down and pass it around, 56 bottles of beer on the wall.
|
||||||
|
|
||||||
|
56 bottles of beer on the wall, 56 bottles of beer.
|
||||||
|
Take one down and pass it around, 55 bottles of beer on the wall.
|
||||||
|
|
||||||
|
55 bottles of beer on the wall, 55 bottles of beer.
|
||||||
|
Take one down and pass it around, 54 bottles of beer on the wall.
|
||||||
|
|
||||||
|
54 bottles of beer on the wall, 54 bottles of beer.
|
||||||
|
Take one down and pass it around, 53 bottles of beer on the wall.
|
||||||
|
|
||||||
|
53 bottles of beer on the wall, 53 bottles of beer.
|
||||||
|
Take one down and pass it around, 52 bottles of beer on the wall.
|
||||||
|
|
||||||
|
52 bottles of beer on the wall, 52 bottles of beer.
|
||||||
|
Take one down and pass it around, 51 bottles of beer on the wall.
|
||||||
|
|
||||||
|
51 bottles of beer on the wall, 51 bottles of beer.
|
||||||
|
Take one down and pass it around, 50 bottles of beer on the wall.
|
||||||
|
|
||||||
|
50 bottles of beer on the wall, 50 bottles of beer.
|
||||||
|
Take one down and pass it around, 49 bottles of beer on the wall.
|
||||||
|
|
||||||
|
49 bottles of beer on the wall, 49 bottles of beer.
|
||||||
|
Take one down and pass it around, 48 bottles of beer on the wall.
|
||||||
|
|
||||||
|
48 bottles of beer on the wall, 48 bottles of beer.
|
||||||
|
Take one down and pass it around, 47 bottles of beer on the wall.
|
||||||
|
|
||||||
|
47 bottles of beer on the wall, 47 bottles of beer.
|
||||||
|
Take one down and pass it around, 46 bottles of beer on the wall.
|
||||||
|
|
||||||
|
46 bottles of beer on the wall, 46 bottles of beer.
|
||||||
|
Take one down and pass it around, 45 bottles of beer on the wall.
|
||||||
|
|
||||||
|
45 bottles of beer on the wall, 45 bottles of beer.
|
||||||
|
Take one down and pass it around, 44 bottles of beer on the wall.
|
||||||
|
|
||||||
|
44 bottles of beer on the wall, 44 bottles of beer.
|
||||||
|
Take one down and pass it around, 43 bottles of beer on the wall.
|
||||||
|
|
||||||
|
43 bottles of beer on the wall, 43 bottles of beer.
|
||||||
|
Take one down and pass it around, 42 bottles of beer on the wall.
|
||||||
|
|
||||||
|
42 bottles of beer on the wall, 42 bottles of beer.
|
||||||
|
Take one down and pass it around, 41 bottles of beer on the wall.
|
||||||
|
|
||||||
|
41 bottles of beer on the wall, 41 bottles of beer.
|
||||||
|
Take one down and pass it around, 40 bottles of beer on the wall.
|
||||||
|
|
||||||
|
40 bottles of beer on the wall, 40 bottles of beer.
|
||||||
|
Take one down and pass it around, 39 bottles of beer on the wall.
|
||||||
|
|
||||||
|
39 bottles of beer on the wall, 39 bottles of beer.
|
||||||
|
Take one down and pass it around, 38 bottles of beer on the wall.
|
||||||
|
|
||||||
|
38 bottles of beer on the wall, 38 bottles of beer.
|
||||||
|
Take one down and pass it around, 37 bottles of beer on the wall.
|
||||||
|
|
||||||
|
37 bottles of beer on the wall, 37 bottles of beer.
|
||||||
|
Take one down and pass it around, 36 bottles of beer on the wall.
|
||||||
|
|
||||||
|
36 bottles of beer on the wall, 36 bottles of beer.
|
||||||
|
Take one down and pass it around, 35 bottles of beer on the wall.
|
||||||
|
|
||||||
|
35 bottles of beer on the wall, 35 bottles of beer.
|
||||||
|
Take one down and pass it around, 34 bottles of beer on the wall.
|
||||||
|
|
||||||
|
34 bottles of beer on the wall, 34 bottles of beer.
|
||||||
|
Take one down and pass it around, 33 bottles of beer on the wall.
|
||||||
|
|
||||||
|
33 bottles of beer on the wall, 33 bottles of beer.
|
||||||
|
Take one down and pass it around, 32 bottles of beer on the wall.
|
||||||
|
|
||||||
|
32 bottles of beer on the wall, 32 bottles of beer.
|
||||||
|
Take one down and pass it around, 31 bottles of beer on the wall.
|
||||||
|
|
||||||
|
31 bottles of beer on the wall, 31 bottles of beer.
|
||||||
|
Take one down and pass it around, 30 bottles of beer on the wall.
|
||||||
|
|
||||||
|
30 bottles of beer on the wall, 30 bottles of beer.
|
||||||
|
Take one down and pass it around, 29 bottles of beer on the wall.
|
||||||
|
|
||||||
|
29 bottles of beer on the wall, 29 bottles of beer.
|
||||||
|
Take one down and pass it around, 28 bottles of beer on the wall.
|
||||||
|
|
||||||
|
28 bottles of beer on the wall, 28 bottles of beer.
|
||||||
|
Take one down and pass it around, 27 bottles of beer on the wall.
|
||||||
|
|
||||||
|
27 bottles of beer on the wall, 27 bottles of beer.
|
||||||
|
Take one down and pass it around, 26 bottles of beer on the wall.
|
||||||
|
|
||||||
|
26 bottles of beer on the wall, 26 bottles of beer.
|
||||||
|
Take one down and pass it around, 25 bottles of beer on the wall.
|
||||||
|
|
||||||
|
25 bottles of beer on the wall, 25 bottles of beer.
|
||||||
|
Take one down and pass it around, 24 bottles of beer on the wall.
|
||||||
|
|
||||||
|
24 bottles of beer on the wall, 24 bottles of beer.
|
||||||
|
Take one down and pass it around, 23 bottles of beer on the wall.
|
||||||
|
|
||||||
|
23 bottles of beer on the wall, 23 bottles of beer.
|
||||||
|
Take one down and pass it around, 22 bottles of beer on the wall.
|
||||||
|
|
||||||
|
22 bottles of beer on the wall, 22 bottles of beer.
|
||||||
|
Take one down and pass it around, 21 bottles of beer on the wall.
|
||||||
|
|
||||||
|
21 bottles of beer on the wall, 21 bottles of beer.
|
||||||
|
Take one down and pass it around, 20 bottles of beer on the wall.
|
||||||
|
|
||||||
|
20 bottles of beer on the wall, 20 bottles of beer.
|
||||||
|
Take one down and pass it around, 19 bottles of beer on the wall.
|
||||||
|
|
||||||
|
19 bottles of beer on the wall, 19 bottles of beer.
|
||||||
|
Take one down and pass it around, 18 bottles of beer on the wall.
|
||||||
|
|
||||||
|
18 bottles of beer on the wall, 18 bottles of beer.
|
||||||
|
Take one down and pass it around, 17 bottles of beer on the wall.
|
||||||
|
|
||||||
|
17 bottles of beer on the wall, 17 bottles of beer.
|
||||||
|
Take one down and pass it around, 16 bottles of beer on the wall.
|
||||||
|
|
||||||
|
16 bottles of beer on the wall, 16 bottles of beer.
|
||||||
|
Take one down and pass it around, 15 bottles of beer on the wall.
|
||||||
|
|
||||||
|
15 bottles of beer on the wall, 15 bottles of beer.
|
||||||
|
Take one down and pass it around, 14 bottles of beer on the wall.
|
||||||
|
|
||||||
|
14 bottles of beer on the wall, 14 bottles of beer.
|
||||||
|
Take one down and pass it around, 13 bottles of beer on the wall.
|
||||||
|
|
||||||
|
13 bottles of beer on the wall, 13 bottles of beer.
|
||||||
|
Take one down and pass it around, 12 bottles of beer on the wall.
|
||||||
|
|
||||||
|
12 bottles of beer on the wall, 12 bottles of beer.
|
||||||
|
Take one down and pass it around, 11 bottles of beer on the wall.
|
||||||
|
|
||||||
|
11 bottles of beer on the wall, 11 bottles of beer.
|
||||||
|
Take one down and pass it around, 10 bottles of beer on the wall.
|
||||||
|
|
||||||
|
10 bottles of beer on the wall, 10 bottles of beer.
|
||||||
|
Take one down and pass it around, 9 bottles of beer on the wall.
|
||||||
|
|
||||||
|
9 bottles of beer on the wall, 9 bottles of beer.
|
||||||
|
Take one down and pass it around, 8 bottles of beer on the wall.
|
||||||
|
|
||||||
|
8 bottles of beer on the wall, 8 bottles of beer.
|
||||||
|
Take one down and pass it around, 7 bottles of beer on the wall.
|
||||||
|
|
||||||
|
7 bottles of beer on the wall, 7 bottles of beer.
|
||||||
|
Take one down and pass it around, 6 bottles of beer on the wall.
|
||||||
|
|
||||||
|
6 bottles of beer on the wall, 6 bottles of beer.
|
||||||
|
Take one down and pass it around, 5 bottles of beer on the wall.
|
||||||
|
|
||||||
|
5 bottles of beer on the wall, 5 bottles of beer.
|
||||||
|
Take one down and pass it around, 4 bottles of beer on the wall.
|
||||||
|
|
||||||
|
4 bottles of beer on the wall, 4 bottles of beer.
|
||||||
|
Take one down and pass it around, 3 bottles of beer on the wall.
|
||||||
|
|
||||||
|
3 bottles of beer on the wall, 3 bottles of beer.
|
||||||
|
Take one down and pass it around, 2 bottles of beer on the wall.
|
||||||
|
|
||||||
|
2 bottles of beer on the wall, 2 bottles of beer.
|
||||||
|
Take one down and pass it around, 1 bottle of beer on the wall.
|
||||||
|
|
||||||
|
1 bottle of beer on the wall, 1 bottle of beer.
|
||||||
|
Take it down and pass it around, no more bottles of beer on the wall.
|
||||||
|
|
||||||
|
No more bottles of beer on the wall, no more bottles of beer.
|
||||||
|
Go to the store and buy some more, 99 bottles of beer on the wall.
|
||||||
|
```
|
||||||
|
|
||||||
|
## For bonus points
|
||||||
|
|
||||||
|
Did you get the tests passing and the code clean? If you want to, these
|
||||||
|
are some additional things you could try:
|
||||||
|
|
||||||
|
* Remove as much duplication as you possibly can.
|
||||||
|
* Optimize for readability, even if it means introducing duplication.
|
||||||
|
* If you've removed all the duplication, do you have a lot of
|
||||||
|
conditionals? Try replacing the conditionals with polymorphism, if it
|
||||||
|
applies in this language. How readable is it?
|
||||||
|
|
||||||
|
Then please share your thoughts in a comment on the submission. Did this
|
||||||
|
experiment make the code better? Worse? Did you learn anything from it?
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Learn to Program by Chris Pine [http://pine.fm/LearnToProgram/?Chapter=06](http://pine.fm/LearnToProgram/?Chapter=06)
|
||||||
|
|
||||||
|
## Submitting Incomplete Problems
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
66
go/beer-song/beer.go
Normal file
66
go/beer-song/beer.go
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
package beer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
// buildBase builds the basic "x bottle(s) of beer"
|
||||||
|
func buildBase(num int) string {
|
||||||
|
var ret string
|
||||||
|
if num == 0 {
|
||||||
|
ret = "No more"
|
||||||
|
} else {
|
||||||
|
ret = strconv.Itoa(num)
|
||||||
|
}
|
||||||
|
ret += " bottle"
|
||||||
|
if num != 1 {
|
||||||
|
ret += "s"
|
||||||
|
}
|
||||||
|
ret += " of beer"
|
||||||
|
return ret
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verse generates a single verse
|
||||||
|
func Verse(num int) (string, error) {
|
||||||
|
var ret string
|
||||||
|
if num > 99 || num < 0 {
|
||||||
|
return "", errors.New("Invalid verse requested")
|
||||||
|
}
|
||||||
|
ret += buildBase(num) + " on the wall, " + strings.ToLower(buildBase(num)) + ".\n"
|
||||||
|
if num == 0 {
|
||||||
|
ret += "Go to the store and buy some more, " + buildBase(99) + " on the wall.\n"
|
||||||
|
} else {
|
||||||
|
ret += "Take "
|
||||||
|
if num == 1 {
|
||||||
|
ret += "it "
|
||||||
|
} else {
|
||||||
|
ret += "one "
|
||||||
|
}
|
||||||
|
ret += "down and pass it around, " + strings.ToLower(buildBase(num-1)) + " on the wall.\n"
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verses generates all verses starting at 'st' and going to 'end'
|
||||||
|
func Verses(st, end int) (string, error) {
|
||||||
|
if st < end {
|
||||||
|
return "", errors.New("Start less than stop")
|
||||||
|
}
|
||||||
|
var r, ret string
|
||||||
|
var err error
|
||||||
|
for i := st; i >= end; i-- {
|
||||||
|
if r, err = Verse(i); err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
ret += r + "\n"
|
||||||
|
}
|
||||||
|
return ret, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Song generates the entire song (all 100 verses)
|
||||||
|
func Song() string {
|
||||||
|
r, _ := Verses(99, 0)
|
||||||
|
return r
|
||||||
|
}
|
139
go/beer-song/beer_test.go
Normal file
139
go/beer-song/beer_test.go
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
package beer
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
const verse8 = "8 bottles of beer on the wall, 8 bottles of beer.\nTake one down and pass it around, 7 bottles of beer on the wall.\n"
|
||||||
|
const verse3 = "3 bottles of beer on the wall, 3 bottles of beer.\nTake one down and pass it around, 2 bottles of beer on the wall.\n"
|
||||||
|
const verse2 = "2 bottles of beer on the wall, 2 bottles of beer.\nTake one down and pass it around, 1 bottle of beer on the wall.\n"
|
||||||
|
const verse1 = "1 bottle of beer on the wall, 1 bottle of beer.\nTake it down and pass it around, no more bottles of beer on the wall.\n"
|
||||||
|
const verse0 = "No more bottles of beer on the wall, no more bottles of beer.\nGo to the store and buy some more, 99 bottles of beer on the wall.\n"
|
||||||
|
|
||||||
|
const verses86 = `8 bottles of beer on the wall, 8 bottles of beer.
|
||||||
|
Take one down and pass it around, 7 bottles of beer on the wall.
|
||||||
|
|
||||||
|
7 bottles of beer on the wall, 7 bottles of beer.
|
||||||
|
Take one down and pass it around, 6 bottles of beer on the wall.
|
||||||
|
|
||||||
|
6 bottles of beer on the wall, 6 bottles of beer.
|
||||||
|
Take one down and pass it around, 5 bottles of beer on the wall.
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
const verses75 = `7 bottles of beer on the wall, 7 bottles of beer.
|
||||||
|
Take one down and pass it around, 6 bottles of beer on the wall.
|
||||||
|
|
||||||
|
6 bottles of beer on the wall, 6 bottles of beer.
|
||||||
|
Take one down and pass it around, 5 bottles of beer on the wall.
|
||||||
|
|
||||||
|
5 bottles of beer on the wall, 5 bottles of beer.
|
||||||
|
Take one down and pass it around, 4 bottles of beer on the wall.
|
||||||
|
|
||||||
|
`
|
||||||
|
|
||||||
|
var verseTestCases = []struct {
|
||||||
|
description string
|
||||||
|
verse int
|
||||||
|
expectedVerse string
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{"a typical verse", 8, verse8, false},
|
||||||
|
{"another typical verse", 3, verse3, false},
|
||||||
|
{"verse 2", 2, verse2, false},
|
||||||
|
{"verse 1", 1, verse1, false},
|
||||||
|
{"verse 0", 0, verse0, false},
|
||||||
|
{"invalid verse", 104, "", true},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestBottlesVerse(t *testing.T) {
|
||||||
|
for _, tt := range verseTestCases {
|
||||||
|
actualVerse, err := Verse(tt.verse)
|
||||||
|
if actualVerse != tt.expectedVerse {
|
||||||
|
t.Fatalf("Verse(%d):\nexpected\n%s\nactual\n%s", tt.verse, tt.expectedVerse, actualVerse)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we expect an error and there isn't one
|
||||||
|
if tt.expectErr && err == nil {
|
||||||
|
t.Errorf("Verse(%d): expected an error, but error is nil", tt.verse)
|
||||||
|
}
|
||||||
|
// if we don't expect an error and there is one
|
||||||
|
if !tt.expectErr && err != nil {
|
||||||
|
t.Errorf("Verse(%d): expected no error, but error is: %s", tt.verse, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var versesTestCases = []struct {
|
||||||
|
description string
|
||||||
|
upperBound int
|
||||||
|
lowerBound int
|
||||||
|
expectedVerse string
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{"multiple verses", 8, 6, verses86, false},
|
||||||
|
{"a different set of verses", 7, 5, verses75, false},
|
||||||
|
{"invalid start", 109, 5, "", true},
|
||||||
|
{"invalid stop", 99, -20, "", true},
|
||||||
|
{"start less than stop", 8, 14, "", true},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestSeveralVerses(t *testing.T) {
|
||||||
|
|
||||||
|
for _, tt := range versesTestCases {
|
||||||
|
actualVerse, err := Verses(tt.upperBound, tt.lowerBound)
|
||||||
|
if actualVerse != tt.expectedVerse {
|
||||||
|
t.Fatalf("Verses(%d, %d):\nexpected\n%s\nactual\n%s", tt.upperBound, tt.lowerBound, tt.expectedVerse, actualVerse)
|
||||||
|
}
|
||||||
|
// if we expect an error and there isn't one
|
||||||
|
if tt.expectErr && err == nil {
|
||||||
|
t.Errorf("Verses(%d, %d): expected an error, but error is nil", tt.upperBound, tt.lowerBound)
|
||||||
|
}
|
||||||
|
// if we don't expect an error and there is one
|
||||||
|
if !tt.expectErr && err != nil {
|
||||||
|
t.Errorf("Verses(%d, %d): expected no error, but error is: %s", tt.upperBound, tt.lowerBound, err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSeveralVerses(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
for _, tt := range versesTestCases {
|
||||||
|
b.StartTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Verses(tt.upperBound, tt.lowerBound)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.StopTimer()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestEntireSong(t *testing.T) {
|
||||||
|
expected, err := Verses(99, 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatalf("unexpected error calling Verses(99,0)")
|
||||||
|
}
|
||||||
|
actual := Song()
|
||||||
|
|
||||||
|
if expected != actual {
|
||||||
|
msg := `
|
||||||
|
Did not sing the whole song correctly.
|
||||||
|
|
||||||
|
Expected:
|
||||||
|
|
||||||
|
%v
|
||||||
|
|
||||||
|
Actual:
|
||||||
|
|
||||||
|
%v
|
||||||
|
`
|
||||||
|
t.Fatalf(msg, expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkEntireSong(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
Song()
|
||||||
|
}
|
||||||
|
}
|
56
go/diffie-hellman/README.md
Normal file
56
go/diffie-hellman/README.md
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
# Diffie Hellman
|
||||||
|
|
||||||
|
Diffie-Hellman key exchange.
|
||||||
|
|
||||||
|
Alice and Bob use Diffie-Hellman key exchange to share secrets. They
|
||||||
|
start with prime numbers, pick private keys, generate and share public
|
||||||
|
keys, and then generate a shared secret key.
|
||||||
|
|
||||||
|
## Step 0
|
||||||
|
|
||||||
|
The test program supplies prime numbers p and g.
|
||||||
|
|
||||||
|
## Step 1
|
||||||
|
|
||||||
|
Alice picks a private key, a, greater than 1 and less than p. Bob does
|
||||||
|
the same to pick a private key b.
|
||||||
|
|
||||||
|
## Step 2
|
||||||
|
|
||||||
|
Alice calculates a public key A.
|
||||||
|
|
||||||
|
A = g**a mod p
|
||||||
|
|
||||||
|
Using the same p and g, Bob similarly calculates a public key B from his
|
||||||
|
private key b.
|
||||||
|
|
||||||
|
## Step 3
|
||||||
|
|
||||||
|
Alice and Bob exchange public keys. Alice calculates secret key s.
|
||||||
|
|
||||||
|
s = B**a mod p
|
||||||
|
|
||||||
|
Bob calculates
|
||||||
|
|
||||||
|
s = A**b mod p
|
||||||
|
|
||||||
|
The calculations produce the same result! Alice and Bob now share
|
||||||
|
secret s.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Wikipedia, 1024 bit key from www.cryptopp.com/wiki. [http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange](http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange)
|
||||||
|
|
||||||
|
## Submitting Incomplete Problems
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
183
go/diffie-hellman/diffie_hellman_test.go
Normal file
183
go/diffie-hellman/diffie_hellman_test.go
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
// Diffie-Hellman-Merkle key exchange
|
||||||
|
//
|
||||||
|
// Step 1: PrivateKey(p *big.Int) *big.Int
|
||||||
|
// Step 2: PublicKey(private, p *big.Int, g int64) *big.Int
|
||||||
|
// Step 2.1: NewPair(p *big.Int, g int64) (private, public *big.Int)
|
||||||
|
// Step 3: SecretKey(private1, public2, p *big.Int) *big.Int
|
||||||
|
//
|
||||||
|
// Private keys should be generated randomly.
|
||||||
|
|
||||||
|
package diffiehellman
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type testCase struct {
|
||||||
|
g int64 // prime, generator
|
||||||
|
p *big.Int // prime, modulus
|
||||||
|
a, b *big.Int // private keys
|
||||||
|
A, B *big.Int // public keys
|
||||||
|
s *big.Int // secret key
|
||||||
|
}
|
||||||
|
|
||||||
|
// WP example
|
||||||
|
var smallTest = testCase{
|
||||||
|
5,
|
||||||
|
big.NewInt(23),
|
||||||
|
big.NewInt(6), big.NewInt(15),
|
||||||
|
big.NewInt(8), big.NewInt(19),
|
||||||
|
big.NewInt(2),
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1024 bit example modulus from cryptopp.com wiki, random private keys
|
||||||
|
var biggerTest = testCase{
|
||||||
|
2,
|
||||||
|
mph("ab359aa76a6773ed7a93b214db0c25d0160817b8a893c001c761e198a3694509" +
|
||||||
|
"ebe87a5313e0349d95083e5412c9fc815bfd61f95ddece43376550fdc624e92f" +
|
||||||
|
"f38a415783b97261204e05d65731bba1ccff0e84c8cd2097b75feca1029261ae" +
|
||||||
|
"19a389a2e15d2939314b184aef707b82eb94412065181d23e04bf065f4ac413f"),
|
||||||
|
|
||||||
|
mph("2f6afe91cb53ecfa463d45cd800c948f7cb83bb9ddc62a07b5b3fd302d0cdf52" +
|
||||||
|
"18ae53ad015a632d137001a3b34239d54715606a292b6cf895b09d7dcf1bdf7a"),
|
||||||
|
|
||||||
|
mph("3651007bfa8a8b1cbaed2ae9326327599249c3bb6e9d8744b7407f3d4732cb8a" +
|
||||||
|
"0708d95c382747bad640d444f135e7e599618d11b15b9ef32e7ac7194e547f4b"),
|
||||||
|
|
||||||
|
mph("57d5489e3858cbd8fae75120907d1521f8e935cce2206d285b11762847e2a4c4" +
|
||||||
|
"a341a4eea18bdd8b40036c8d0004ffc323d5ae19da55176b08ff6f2d0ac97c65" +
|
||||||
|
"357c1f16756a6901ff926c8544c8af0a90ed2705966851f79a115cb77aac66be" +
|
||||||
|
"ceff569aadd7f02859539c28d55c08c62a03e45613bc52d205ace0704ea7c610"),
|
||||||
|
|
||||||
|
mph("6b189a36db5ca3ff83b66fb2c226078294c323f4c7cef35c506c237b0db7906d" +
|
||||||
|
"64cceb05af15a3603a30fd49834d3a6971d917f520d9a577c159d3b7d2bd8813" +
|
||||||
|
"5d19db47a9618340e4a51ec8845dbf5d50a4c6f14d6161def1eeaacecee8018f" +
|
||||||
|
"8816113a294959399989b759f4618e35dbffc570ab2a5a74ac59fccef35f684c"),
|
||||||
|
|
||||||
|
mph("64f74babc466f8e56d9b77ce2cc65d65fe1603b931c018b98a2a615d66172590" +
|
||||||
|
"803a94ac230db02de4b8ae567497c1844a6f7bd5bed69b95d3137acc1a6462d5" +
|
||||||
|
"aeba5b2b83a0e6b8ed4c072e5135a57c87b654ebe04cf128bbff49ee06df33b7" +
|
||||||
|
"8615e0067fdc9df22f7673b1e0501fb57598c7bff9ff173ddff47270fbd6f98f"),
|
||||||
|
}
|
||||||
|
|
||||||
|
// must parse hex, short name contrived just to make test data line up with
|
||||||
|
// tab width 4.
|
||||||
|
func mph(h string) *big.Int {
|
||||||
|
p, ok := new(big.Int).SetString(h, 16)
|
||||||
|
if !ok {
|
||||||
|
panic("invalid hex: " + h)
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
var tests = []testCase{
|
||||||
|
smallTest,
|
||||||
|
biggerTest,
|
||||||
|
}
|
||||||
|
|
||||||
|
var _one = big.NewInt(1)
|
||||||
|
|
||||||
|
// test that PrivateKey returns numbers in range, returns different numbers.
|
||||||
|
func TestPrivateKey(t *testing.T) {
|
||||||
|
priv := func(p *big.Int) *big.Int {
|
||||||
|
a := PrivateKey(p)
|
||||||
|
if a.Cmp(_one) <= 0 || a.Cmp(p) >= 0 {
|
||||||
|
t.Fatalf("PrivateKey(%d) = %d, out of range (1, %d)", p, a, p)
|
||||||
|
}
|
||||||
|
return a
|
||||||
|
}
|
||||||
|
ms := map[string]bool{}
|
||||||
|
mb := map[string]bool{}
|
||||||
|
for i := 0; i < 100; i++ {
|
||||||
|
ms[priv(smallTest.p).String()] = true
|
||||||
|
mb[priv(biggerTest.p).String()] = true
|
||||||
|
}
|
||||||
|
if len(ms) == 1 {
|
||||||
|
t.Fatalf("For prime %d same key generated every time. "+
|
||||||
|
"Want random keys.", smallTest.p)
|
||||||
|
}
|
||||||
|
if len(mb) < 100 {
|
||||||
|
t.Fatal("For prime %d duplicate keys generated. "+
|
||||||
|
"Want unique keys.", biggerTest.p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test that PublicKey returns known results.
|
||||||
|
func TestPublicKey(t *testing.T) {
|
||||||
|
tp := func(a, A, p *big.Int, g int64) {
|
||||||
|
if k := PublicKey(a, p, g); k.Cmp(A) != 0 {
|
||||||
|
t.Fatalf("PublicKey(%x,\n%x,\n%d)\n= %x,\nwant %x.",
|
||||||
|
a, p, g, k, A)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
tp(test.a, test.A, test.p, test.g)
|
||||||
|
tp(test.b, test.B, test.p, test.g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test that SecretKey returns known results.
|
||||||
|
func TestSecretKeys(t *testing.T) {
|
||||||
|
tp := func(a, B, p, s *big.Int) {
|
||||||
|
if k := SecretKey(a, B, p); k.Cmp(s) != 0 {
|
||||||
|
t.Fatalf("SecretKey(%x,\n%x,\n%x)\n= %x,\nwant %x.",
|
||||||
|
a, B, p, k, s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for _, test := range tests {
|
||||||
|
tp(test.a, test.B, test.p, test.s)
|
||||||
|
tp(test.b, test.A, test.p, test.s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// test that NewPair produces working keys
|
||||||
|
func TestNewPair(t *testing.T) {
|
||||||
|
p, g := biggerTest.p, biggerTest.g
|
||||||
|
test := func(a, A *big.Int) {
|
||||||
|
if a.Cmp(_one) <= 0 || a.Cmp(p) >= 0 {
|
||||||
|
t.Fatalf("NewPair(%d, %d) private key = %d, out of range (1, %d)",
|
||||||
|
p, g, a, p)
|
||||||
|
}
|
||||||
|
if A.Cmp(_one) <= 0 || A.Cmp(p) >= 0 {
|
||||||
|
t.Fatalf("NewPair(%d, %d) public key = %d, out of range (1, %d)",
|
||||||
|
p, g, A, p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
a, A := NewPair(p, g)
|
||||||
|
test(a, A)
|
||||||
|
for i := 0; i < 20; i++ {
|
||||||
|
b, B := NewPair(p, g)
|
||||||
|
test(b, B)
|
||||||
|
sa := SecretKey(a, B, p)
|
||||||
|
sb := SecretKey(b, A, p)
|
||||||
|
if sa.Cmp(sb) != 0 {
|
||||||
|
t.Fatalf("NewPair() produced non-working keys.")
|
||||||
|
}
|
||||||
|
a, A = b, B
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPrivateKey(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
PrivateKey(biggerTest.p)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkPublicKey(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
PublicKey(biggerTest.a, biggerTest.p, biggerTest.g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkNewPair(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
NewPair(biggerTest.p, biggerTest.g)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkSecretKey(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
SecretKey(biggerTest.a, biggerTest.B, biggerTest.p)
|
||||||
|
}
|
||||||
|
}
|
34
go/diffie-hellman/diffiehellman.go
Normal file
34
go/diffie-hellman/diffiehellman.go
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
package diffiehellman
|
||||||
|
|
||||||
|
import (
|
||||||
|
"math/big"
|
||||||
|
"math/rand"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Random number generator
|
||||||
|
var rnd = rand.New(rand.NewSource(time.Now().UnixNano()))
|
||||||
|
|
||||||
|
// PrivateKey generates a number greater than 1 and less than p
|
||||||
|
func PrivateKey(p *big.Int) *big.Int {
|
||||||
|
ret := &big.Int{}
|
||||||
|
return ret.Add(big.NewInt(2), ret.Rand(rnd, ret.Sub(p, big.NewInt(2))))
|
||||||
|
}
|
||||||
|
|
||||||
|
// PublicKey generates the public key for private key p
|
||||||
|
func PublicKey(pKey, p *big.Int, g int64) *big.Int {
|
||||||
|
ret := big.NewInt(g)
|
||||||
|
return ret.Exp(ret, pKey, p)
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewPair generates a public/private key pair from given primes p & g
|
||||||
|
func NewPair(p *big.Int, g int64) (*big.Int, *big.Int) {
|
||||||
|
priv := PrivateKey(p)
|
||||||
|
return priv, PublicKey(priv, p, g)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SecretKey returns a secret key given private & public keys and the prime p
|
||||||
|
func SecretKey(priv, pub, p *big.Int) *big.Int {
|
||||||
|
ret := &big.Int{}
|
||||||
|
return ret.Exp(pub, priv, p)
|
||||||
|
}
|
@ -2,21 +2,21 @@ package prime
|
|||||||
|
|
||||||
var sieve []int
|
var sieve []int
|
||||||
|
|
||||||
|
// Nth finds the nth prime and 'true' if the 0th prime wasn't requested
|
||||||
func Nth(n int) (int, bool) {
|
func Nth(n int) (int, bool) {
|
||||||
if len(sieve) == 0 {
|
|
||||||
sieve = append(sieve, 0)
|
|
||||||
sieve = append(sieve, 2)
|
|
||||||
}
|
|
||||||
if n == 0 {
|
if n == 0 {
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
if len(sieve) == 0 {
|
||||||
for i := sieve[len(sieve)-1]; n <= len(sieve); i++ {
|
// Let's just do some initialization
|
||||||
// Check if i is a prime
|
sieve = append(sieve, 0)
|
||||||
|
sieve = append(sieve, 2)
|
||||||
|
}
|
||||||
|
sieveLen := len(sieve)
|
||||||
|
for i := sieve[len(sieve)-1]; sieveLen <= n; i++ {
|
||||||
isPrime := true
|
isPrime := true
|
||||||
for j := 1; j < len(sieve); j++ {
|
for j := 1; j < sieveLen; j++ {
|
||||||
if i%sieve[j] == 0 {
|
if i%sieve[j] == 0 {
|
||||||
// Not a prime
|
|
||||||
isPrime = false
|
isPrime = false
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
@ -24,9 +24,7 @@ func Nth(n int) (int, bool) {
|
|||||||
if isPrime {
|
if isPrime {
|
||||||
// Found a new prime
|
// Found a new prime
|
||||||
sieve = append(sieve, i)
|
sieve = append(sieve, i)
|
||||||
if len(sieve) >= n {
|
sieveLen = len(sieve)
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return sieve[n], true
|
return sieve[n], true
|
||||||
|
96
go/ocr-numbers/README.md
Normal file
96
go/ocr-numbers/README.md
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
# Ocr Numbers
|
||||||
|
|
||||||
|
Write a program that, given a 3 x 4 grid of pipes, underscores, and spaces, can determine which number is represented, or whether it is garbled.
|
||||||
|
|
||||||
|
# Step One
|
||||||
|
|
||||||
|
To begin with, convert a simple binary font to a string containing 0 or 1.
|
||||||
|
|
||||||
|
The binary font uses pipes and underscores, four rows high and three columns wide.
|
||||||
|
|
||||||
|
```
|
||||||
|
_ #
|
||||||
|
| | # zero.
|
||||||
|
|_| #
|
||||||
|
# the fourth row is always blank
|
||||||
|
```
|
||||||
|
|
||||||
|
Is converted to "0"
|
||||||
|
|
||||||
|
```
|
||||||
|
#
|
||||||
|
| # one.
|
||||||
|
| #
|
||||||
|
# (blank fourth row)
|
||||||
|
```
|
||||||
|
|
||||||
|
Is converted to "1"
|
||||||
|
|
||||||
|
If the input is the correct size, but not recognizable, your program should return '?'
|
||||||
|
|
||||||
|
If the input is the incorrect size, your program should return an error.
|
||||||
|
|
||||||
|
# Step Two
|
||||||
|
|
||||||
|
Update your program to recognize multi-character binary strings, replacing garbled numbers with ?
|
||||||
|
|
||||||
|
# Step Three
|
||||||
|
|
||||||
|
Update your program to recognize all numbers 0 through 9, both individually and as part of a larger string.
|
||||||
|
|
||||||
|
```
|
||||||
|
_
|
||||||
|
_|
|
||||||
|
|_
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Is converted to "2"
|
||||||
|
|
||||||
|
```
|
||||||
|
_ _ _ _ _ _ _ _ #
|
||||||
|
| _| _||_||_ |_ ||_||_|| | # decimal numbers.
|
||||||
|
||_ _| | _||_| ||_| _||_| #
|
||||||
|
# fourth line is always blank
|
||||||
|
```
|
||||||
|
|
||||||
|
Is converted to "1234567890"
|
||||||
|
|
||||||
|
# Step Four
|
||||||
|
|
||||||
|
Update your program to handle multiple numbers, one per line. When converting several lines, join the lines with commas.
|
||||||
|
|
||||||
|
```
|
||||||
|
_ _
|
||||||
|
| _| _|
|
||||||
|
||_ _|
|
||||||
|
|
||||||
|
_ _
|
||||||
|
|_||_ |_
|
||||||
|
| _||_|
|
||||||
|
|
||||||
|
_ _ _
|
||||||
|
||_||_|
|
||||||
|
||_| _|
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
Is converted to "123,456,789"
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Inspired by the Bank OCR kata [http://codingdojo.org/cgi-bin/wiki.pl?KataBankOCR](http://codingdojo.org/cgi-bin/wiki.pl?KataBankOCR)
|
||||||
|
|
||||||
|
## Submitting Incomplete Problems
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
65
go/ocr-numbers/ocr.go
Normal file
65
go/ocr-numbers/ocr.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package ocr
|
||||||
|
|
||||||
|
import "strings"
|
||||||
|
|
||||||
|
// recognizeDigit takes a 3x4 grid of pipes, underscores, and spaces
|
||||||
|
// and determines the digit represented.
|
||||||
|
func recognizeDigit(in string) string {
|
||||||
|
switch in {
|
||||||
|
case "\n _ \n| |\n|_|\n ":
|
||||||
|
return "0"
|
||||||
|
case "\n \n |\n |\n ":
|
||||||
|
return "1"
|
||||||
|
case "\n _ \n _|\n|_ \n ":
|
||||||
|
return "2"
|
||||||
|
case "\n _ \n _|\n _|\n ":
|
||||||
|
return "3"
|
||||||
|
case "\n \n|_|\n |\n ":
|
||||||
|
return "4"
|
||||||
|
case "\n _ \n|_ \n _|\n ":
|
||||||
|
return "5"
|
||||||
|
case "\n _ \n|_ \n|_|\n ":
|
||||||
|
return "6"
|
||||||
|
case "\n _ \n |\n |\n ":
|
||||||
|
return "7"
|
||||||
|
case "\n _ \n|_|\n|_|\n ":
|
||||||
|
return "8"
|
||||||
|
case "\n _ \n|_|\n _|\n ":
|
||||||
|
return "9"
|
||||||
|
}
|
||||||
|
return "?"
|
||||||
|
}
|
||||||
|
|
||||||
|
// parseChar takes 3 lines and a number and returns
|
||||||
|
// the string value of that character
|
||||||
|
func parseChar(lines []string, num int) string {
|
||||||
|
startIdx := 3 * num
|
||||||
|
lenNeed := startIdx + 3
|
||||||
|
if len(lines[0]) < lenNeed || len(lines[1]) < lenNeed {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
char := "\n" + lines[0][(startIdx+0):(startIdx+3)]
|
||||||
|
char += "\n" + lines[1][(startIdx+0):(startIdx+3)]
|
||||||
|
char += "\n" + lines[2][(startIdx+0):(startIdx+3)]
|
||||||
|
char += "\n" + lines[3][(startIdx+0):(startIdx+3)]
|
||||||
|
return recognizeDigit(char)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recognize takes a string, splits it up by \n and
|
||||||
|
// then sends 4 line chunks and calls parseChar on it
|
||||||
|
func Recognize(in string) []string {
|
||||||
|
var ret []string
|
||||||
|
lines := strings.Split(in, "\n")
|
||||||
|
numRet := len(lines) / 4
|
||||||
|
for i := 0; i < numRet; i++ {
|
||||||
|
var retString string
|
||||||
|
startIdx := (i * 4) + 1
|
||||||
|
procLines := lines[startIdx : startIdx+4]
|
||||||
|
numChars := len(lines[startIdx]) / 3
|
||||||
|
for j := 0; j < numChars; j++ {
|
||||||
|
retString += parseChar(procLines, j)
|
||||||
|
}
|
||||||
|
ret = append(ret, retString)
|
||||||
|
}
|
||||||
|
return ret
|
||||||
|
}
|
130
go/ocr-numbers/ocr_numbers_test.go
Normal file
130
go/ocr-numbers/ocr_numbers_test.go
Normal file
@ -0,0 +1,130 @@
|
|||||||
|
// Go requirements:
|
||||||
|
//
|
||||||
|
// Define a function recognizeDigit as README Step 1 except make it recognize
|
||||||
|
// all ten digits 0 to 9. Pick what you like for parameters and return values
|
||||||
|
// but make it useful as a subroutine for README step 2.
|
||||||
|
//
|
||||||
|
// For README Step 2 define,
|
||||||
|
//
|
||||||
|
// func Recognize(string) []string
|
||||||
|
//
|
||||||
|
// and implement it using recognizeDigit.
|
||||||
|
//
|
||||||
|
// Input strings tested here have a \n at the beginning of each line and
|
||||||
|
// no trailing \n on the last line. (This makes for readable raw string
|
||||||
|
// literals.)
|
||||||
|
//
|
||||||
|
// For bonus points, gracefully handle misformatted data. What should you
|
||||||
|
// do with a partial cell? Discard it? Pad with spaces? Report it with a
|
||||||
|
// "?" character? What should you do if the first character is not \n?
|
||||||
|
|
||||||
|
package ocr
|
||||||
|
|
||||||
|
import (
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
in string
|
||||||
|
out []string
|
||||||
|
}{
|
||||||
|
{`
|
||||||
|
_
|
||||||
|
| |
|
||||||
|
|_|
|
||||||
|
`, []string{"0"}},
|
||||||
|
{`
|
||||||
|
|
||||||
|
|
|
||||||
|
|
|
||||||
|
`, []string{"1"}},
|
||||||
|
{`
|
||||||
|
_
|
||||||
|
_|
|
||||||
|
|_
|
||||||
|
`, []string{"2"}},
|
||||||
|
{`
|
||||||
|
_
|
||||||
|
_|
|
||||||
|
_|
|
||||||
|
`, []string{"3"}},
|
||||||
|
{`
|
||||||
|
|
||||||
|
|_|
|
||||||
|
|
|
||||||
|
`, []string{"4"}},
|
||||||
|
{`
|
||||||
|
_
|
||||||
|
|_
|
||||||
|
_|
|
||||||
|
`, []string{"5"}},
|
||||||
|
{`
|
||||||
|
_
|
||||||
|
|_
|
||||||
|
|_|
|
||||||
|
`, []string{"6"}},
|
||||||
|
{`
|
||||||
|
_
|
||||||
|
|
|
||||||
|
|
|
||||||
|
`, []string{"7"}},
|
||||||
|
{`
|
||||||
|
_
|
||||||
|
|_|
|
||||||
|
|_|
|
||||||
|
`, []string{"8"}},
|
||||||
|
{`
|
||||||
|
_
|
||||||
|
|_|
|
||||||
|
_|
|
||||||
|
`, []string{"9"}},
|
||||||
|
{`
|
||||||
|
_
|
||||||
|
|| |
|
||||||
|
||_|
|
||||||
|
`, []string{"10"}},
|
||||||
|
{`
|
||||||
|
|
||||||
|
| |
|
||||||
|
| |
|
||||||
|
`, []string{"?"}},
|
||||||
|
{`
|
||||||
|
_ _ _ _
|
||||||
|
| || | || | | || || |
|
||||||
|
| ||_| ||_| | ||_||_|
|
||||||
|
`, []string{"110101100"}},
|
||||||
|
{`
|
||||||
|
_ _ _
|
||||||
|
| || | || | || || |
|
||||||
|
| | _| ||_| | ||_||_|
|
||||||
|
`, []string{"11?10?1?0"}},
|
||||||
|
{`
|
||||||
|
_ _ _ _ _ _ _ _
|
||||||
|
| _| _||_||_ |_ ||_||_|| |
|
||||||
|
||_ _| | _||_| ||_| _||_|
|
||||||
|
`, []string{"1234567890"}},
|
||||||
|
{`
|
||||||
|
_ _
|
||||||
|
| _| _|
|
||||||
|
||_ _|
|
||||||
|
|
||||||
|
_ _
|
||||||
|
|_||_ |_
|
||||||
|
| _||_|
|
||||||
|
|
||||||
|
_ _ _
|
||||||
|
||_||_|
|
||||||
|
||_| _|
|
||||||
|
`, []string{"123", "456", "789"}},
|
||||||
|
}
|
||||||
|
|
||||||
|
var _ = recognizeDigit // step 1.
|
||||||
|
|
||||||
|
func TestRecognize(t *testing.T) {
|
||||||
|
for _, test := range tests {
|
||||||
|
if res := Recognize(test.in); !reflect.DeepEqual(res, test.out) {
|
||||||
|
t.Fatalf("Recognize(`%s`) = %q, want %q.", test.in, res, test.out)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
59
go/octal/README.md
Normal file
59
go/octal/README.md
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# Octal
|
||||||
|
|
||||||
|
Write a program that will convert a octal number, represented as a string (e.g. '1735263'), to its decimal equivalent using first principles (i.e. no, you may not use built-in or external libraries to accomplish the conversion).
|
||||||
|
|
||||||
|
Implement octal to decimal conversion. Given an octal input
|
||||||
|
string, your program should produce a decimal output.
|
||||||
|
|
||||||
|
## Note
|
||||||
|
- Implement the conversion yourself.
|
||||||
|
Do not use something else to perform the conversion for you.
|
||||||
|
- Treat invalid input as octal 0.
|
||||||
|
|
||||||
|
## About Octal (Base-8)
|
||||||
|
Decimal is a base-10 system.
|
||||||
|
|
||||||
|
A number 233 in base 10 notation can be understood
|
||||||
|
as a linear combination of powers of 10:
|
||||||
|
|
||||||
|
- The rightmost digit gets multiplied by 10^0 = 1
|
||||||
|
- The next number gets multiplied by 10^1 = 10
|
||||||
|
- ...
|
||||||
|
- The *n*th number gets multiplied by 10^*(n-1)*.
|
||||||
|
- All these values are summed.
|
||||||
|
|
||||||
|
So:
|
||||||
|
```
|
||||||
|
233 # decimal
|
||||||
|
= 2*10^2 + 3*10^1 + 3*10^0
|
||||||
|
= 2*100 + 3*10 + 3*1
|
||||||
|
```
|
||||||
|
|
||||||
|
Octal is similar, but uses powers of 8 rather than powers of 10.
|
||||||
|
|
||||||
|
So:
|
||||||
|
```
|
||||||
|
233 # octal
|
||||||
|
= 2*8^2 + 3*8^1 + 3*8^0
|
||||||
|
= 2*64 + 3*8 + 3*1
|
||||||
|
= 128 + 24 + 3
|
||||||
|
= 155
|
||||||
|
```
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
All of Computer Science [http://www.wolframalpha.com/input/?i=base+8](http://www.wolframalpha.com/input/?i=base+8)
|
||||||
|
|
||||||
|
## Submitting Incomplete Problems
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
24
go/octal/octal.go
Normal file
24
go/octal/octal.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
package octal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"math"
|
||||||
|
)
|
||||||
|
|
||||||
|
// ParseOctal takes a string representation of an octal number
|
||||||
|
// and returns the decimal value of that number, or an error if it
|
||||||
|
// was unparseable as an octal number
|
||||||
|
func ParseOctal(v string) (int64, error) {
|
||||||
|
var ret float64
|
||||||
|
octLen := float64(len(v))
|
||||||
|
for i := range v {
|
||||||
|
octLen--
|
||||||
|
switch {
|
||||||
|
case v[i] > 47 && v[i] < 56:
|
||||||
|
ret = ret + float64(v[i]-48)*math.Pow(8, octLen)
|
||||||
|
default:
|
||||||
|
return 0, errors.New("Unparseable as octal")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return int64(ret), nil
|
||||||
|
}
|
50
go/octal/octal_test.go
Normal file
50
go/octal/octal_test.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package octal
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
var testCases = []struct {
|
||||||
|
input string
|
||||||
|
expectedNum int64
|
||||||
|
expectErr bool
|
||||||
|
}{
|
||||||
|
{"1", 1, false},
|
||||||
|
{"10", 8, false},
|
||||||
|
{"1234567", 342391, false},
|
||||||
|
{"carrot", 0, true},
|
||||||
|
{"35682", 0, true},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestParseOctal(t *testing.T) {
|
||||||
|
for _, test := range testCases {
|
||||||
|
actualNum, actualErr := ParseOctal(test.input)
|
||||||
|
if actualNum != test.expectedNum {
|
||||||
|
t.Fatalf("ParseOctal(%s): expected[%d], actual [%d]",
|
||||||
|
test.input, test.expectedNum, actualNum)
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we expect an error and there isn't one
|
||||||
|
if test.expectErr && actualErr == nil {
|
||||||
|
t.Errorf("ParseOctal(%s): expected an error, but error is nil", test.input)
|
||||||
|
}
|
||||||
|
// if we don't expect an error and there is one
|
||||||
|
if !test.expectErr && actualErr != nil {
|
||||||
|
t.Errorf("ParseOctal(%s): expected no error, but error is: %s", test.input, actualErr)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func BenchmarkParseOctal(b *testing.B) {
|
||||||
|
b.StopTimer()
|
||||||
|
|
||||||
|
for _, test := range testCases {
|
||||||
|
b.StartTimer()
|
||||||
|
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
ParseOctal(test.input)
|
||||||
|
}
|
||||||
|
|
||||||
|
b.StopTimer()
|
||||||
|
}
|
||||||
|
}
|
89
go/wordy/README.md
Normal file
89
go/wordy/README.md
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# Wordy
|
||||||
|
|
||||||
|
Write a program that takes a word problem and returns the answer as an integer.
|
||||||
|
|
||||||
|
## Step 1
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
|
||||||
|
> What is 5 plus 13?
|
||||||
|
|
||||||
|
The program should handle large numbers and negative numbers.
|
||||||
|
|
||||||
|
Remember, that these are verbal word problems, not treated as you
|
||||||
|
normally would treat a written problem. This means that you calculate
|
||||||
|
as you move forward each step. In other words, you should ignore order
|
||||||
|
of operations. 3 + 2 * 3 = 15, not 9.
|
||||||
|
|
||||||
|
Use the tests to drive your solution by deleting the `skip` in one test
|
||||||
|
at a time.
|
||||||
|
|
||||||
|
## Step 2
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
|
||||||
|
> What is 5 plus 13?
|
||||||
|
|
||||||
|
> What is 7 minus 5?
|
||||||
|
|
||||||
|
> What is 6 multiplied by 4?
|
||||||
|
|
||||||
|
> What is 25 divided by 5?
|
||||||
|
|
||||||
|
## Step 3
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
|
||||||
|
> What is 5 plus 13 plus 6?
|
||||||
|
|
||||||
|
> What is 7 minus 5 minus 1?
|
||||||
|
|
||||||
|
> What is 9 minus 3 plus 5?
|
||||||
|
|
||||||
|
> What is 3 plus 5 minus 8?
|
||||||
|
|
||||||
|
## Step 4
|
||||||
|
|
||||||
|
E.g.
|
||||||
|
|
||||||
|
> What is 5 plus 13?
|
||||||
|
|
||||||
|
> What is 7 minus 5?
|
||||||
|
|
||||||
|
> What is 6 times 4?
|
||||||
|
|
||||||
|
> What is 25 divided by 5?
|
||||||
|
|
||||||
|
> What is 78 plus 5 minus 3?
|
||||||
|
|
||||||
|
> What is 18 times 3 plus 16?
|
||||||
|
|
||||||
|
> What is 4 times 3 divided by 6?
|
||||||
|
|
||||||
|
> What is 4 plus 3 times 2?
|
||||||
|
|
||||||
|
## Extensions
|
||||||
|
|
||||||
|
Implement questions of the type:
|
||||||
|
|
||||||
|
> What is 2 raised to the 5th power?
|
||||||
|
|
||||||
|
Remember to write failing tests for this code.
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
Inspired by one of the generated questions in the Extreme Startup game. [https://github.com/rchatley/extreme_startup](https://github.com/rchatley/extreme_startup)
|
||||||
|
|
||||||
|
## Submitting Incomplete Problems
|
||||||
|
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||||
|
|
50
go/wordy/wordy_test.go
Normal file
50
go/wordy/wordy_test.go
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
package wordy
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
var tests = []struct {
|
||||||
|
q string
|
||||||
|
a int
|
||||||
|
ok bool
|
||||||
|
}{
|
||||||
|
{"What is 1 plus 1?", 2, true},
|
||||||
|
{"What is 53 plus 2?", 55, true},
|
||||||
|
{"What is -1 plus -10?", -11, true},
|
||||||
|
{"What is 123 plus 45678?", 45801, true},
|
||||||
|
{"What is 4 minus -12?", 16, true},
|
||||||
|
{"What is -3 multiplied by 25?", -75, true},
|
||||||
|
{"What is 33 divided by -3?", -11, true},
|
||||||
|
{"What is 1 plus 1 plus 1?", 3, true},
|
||||||
|
{"What is 1 plus 5 minus -2?", 8, true},
|
||||||
|
{"What is 20 minus 4 minus 13?", 3, true},
|
||||||
|
{"What is 17 minus 6 plus 3?", 14, true},
|
||||||
|
{"What is 2 multiplied by -2 multiplied by 3?", -12, true},
|
||||||
|
{"What is -3 plus 7 multiplied by -2?", -8, true},
|
||||||
|
{"What is -12 divided by 2 divided by -3?", 2, true},
|
||||||
|
{"What is 53 cubed?", 0, false},
|
||||||
|
{"Who is the president of the United States?", 0, false},
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestAnswer(t *testing.T) {
|
||||||
|
for _, test := range tests {
|
||||||
|
switch a, ok := Answer(test.q); {
|
||||||
|
case !ok:
|
||||||
|
if test.ok {
|
||||||
|
t.Errorf("Answer(%q) returned ok = false, expecting true.", test.q)
|
||||||
|
}
|
||||||
|
case !test.ok:
|
||||||
|
t.Errorf("Answer(%q) = %d, %t, expecting ok = false.", test.q, a, ok)
|
||||||
|
case a != test.a:
|
||||||
|
t.Errorf("Answer(%q) = %d, want %d.", test.q, a, test.a)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Benchmark combined time to answer all questions.
|
||||||
|
func BenchmarkAnswer(b *testing.B) {
|
||||||
|
for i := 0; i < b.N; i++ {
|
||||||
|
for _, test := range tests {
|
||||||
|
Answer(test.q)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user