From ec45e6b2ebd0dc16b60f687660335c5180c6b387 Mon Sep 17 00:00:00 2001 From: Brian Buller Date: Fri, 2 Sep 2016 14:26:22 -0500 Subject: [PATCH] Updating all of the new ones that are done. --- go/beer-song/README.md | 339 +++++++++++++++++++++++ go/beer-song/beer.go | 66 +++++ go/beer-song/beer_test.go | 139 ++++++++++ go/diffie-hellman/README.md | 56 ++++ go/diffie-hellman/diffie_hellman_test.go | 183 ++++++++++++ go/diffie-hellman/diffiehellman.go | 34 +++ go/nth-prime/nth_prime.go | 22 +- go/ocr-numbers/README.md | 96 +++++++ go/ocr-numbers/ocr.go | 65 +++++ go/ocr-numbers/ocr_numbers_test.go | 130 +++++++++ go/octal/README.md | 59 ++++ go/octal/octal.go | 24 ++ go/octal/octal_test.go | 50 ++++ go/wordy/README.md | 89 ++++++ go/wordy/wordy_test.go | 50 ++++ 15 files changed, 1390 insertions(+), 12 deletions(-) create mode 100644 go/beer-song/README.md create mode 100644 go/beer-song/beer.go create mode 100644 go/beer-song/beer_test.go create mode 100644 go/diffie-hellman/README.md create mode 100644 go/diffie-hellman/diffie_hellman_test.go create mode 100644 go/diffie-hellman/diffiehellman.go create mode 100644 go/ocr-numbers/README.md create mode 100644 go/ocr-numbers/ocr.go create mode 100644 go/ocr-numbers/ocr_numbers_test.go create mode 100644 go/octal/README.md create mode 100644 go/octal/octal.go create mode 100644 go/octal/octal_test.go create mode 100644 go/wordy/README.md create mode 100644 go/wordy/wordy_test.go diff --git a/go/beer-song/README.md b/go/beer-song/README.md new file mode 100644 index 0000000..889cf25 --- /dev/null +++ b/go/beer-song/README.md @@ -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. + diff --git a/go/beer-song/beer.go b/go/beer-song/beer.go new file mode 100644 index 0000000..cd7fca6 --- /dev/null +++ b/go/beer-song/beer.go @@ -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 +} diff --git a/go/beer-song/beer_test.go b/go/beer-song/beer_test.go new file mode 100644 index 0000000..38809c8 --- /dev/null +++ b/go/beer-song/beer_test.go @@ -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() + } +} diff --git a/go/diffie-hellman/README.md b/go/diffie-hellman/README.md new file mode 100644 index 0000000..feef92d --- /dev/null +++ b/go/diffie-hellman/README.md @@ -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. + diff --git a/go/diffie-hellman/diffie_hellman_test.go b/go/diffie-hellman/diffie_hellman_test.go new file mode 100644 index 0000000..9d5afe5 --- /dev/null +++ b/go/diffie-hellman/diffie_hellman_test.go @@ -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) + } +} diff --git a/go/diffie-hellman/diffiehellman.go b/go/diffie-hellman/diffiehellman.go new file mode 100644 index 0000000..e409d0f --- /dev/null +++ b/go/diffie-hellman/diffiehellman.go @@ -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) +} diff --git a/go/nth-prime/nth_prime.go b/go/nth-prime/nth_prime.go index 9cbea87..cbcbb89 100644 --- a/go/nth-prime/nth_prime.go +++ b/go/nth-prime/nth_prime.go @@ -2,21 +2,21 @@ package prime var sieve []int +// Nth finds the nth prime and 'true' if the 0th prime wasn't requested func Nth(n int) (int, bool) { - if len(sieve) == 0 { - sieve = append(sieve, 0) - sieve = append(sieve, 2) - } if n == 0 { return 0, false } - - for i := sieve[len(sieve)-1]; n <= len(sieve); i++ { - // Check if i is a prime + if len(sieve) == 0 { + // Let's just do some initialization + sieve = append(sieve, 0) + sieve = append(sieve, 2) + } + sieveLen := len(sieve) + for i := sieve[len(sieve)-1]; sieveLen <= n; i++ { isPrime := true - for j := 1; j < len(sieve); j++ { + for j := 1; j < sieveLen; j++ { if i%sieve[j] == 0 { - // Not a prime isPrime = false break } @@ -24,9 +24,7 @@ func Nth(n int) (int, bool) { if isPrime { // Found a new prime sieve = append(sieve, i) - if len(sieve) >= n { - break - } + sieveLen = len(sieve) } } return sieve[n], true diff --git a/go/ocr-numbers/README.md b/go/ocr-numbers/README.md new file mode 100644 index 0000000..9b212ad --- /dev/null +++ b/go/ocr-numbers/README.md @@ -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. + diff --git a/go/ocr-numbers/ocr.go b/go/ocr-numbers/ocr.go new file mode 100644 index 0000000..fa6243e --- /dev/null +++ b/go/ocr-numbers/ocr.go @@ -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 +} diff --git a/go/ocr-numbers/ocr_numbers_test.go b/go/ocr-numbers/ocr_numbers_test.go new file mode 100644 index 0000000..707a91a --- /dev/null +++ b/go/ocr-numbers/ocr_numbers_test.go @@ -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) + } + } +} diff --git a/go/octal/README.md b/go/octal/README.md new file mode 100644 index 0000000..330b5c9 --- /dev/null +++ b/go/octal/README.md @@ -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. + diff --git a/go/octal/octal.go b/go/octal/octal.go new file mode 100644 index 0000000..daa4ea4 --- /dev/null +++ b/go/octal/octal.go @@ -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 +} diff --git a/go/octal/octal_test.go b/go/octal/octal_test.go new file mode 100644 index 0000000..35247ee --- /dev/null +++ b/go/octal/octal_test.go @@ -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() + } +} diff --git a/go/wordy/README.md b/go/wordy/README.md new file mode 100644 index 0000000..09c35b6 --- /dev/null +++ b/go/wordy/README.md @@ -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. + diff --git a/go/wordy/wordy_test.go b/go/wordy/wordy_test.go new file mode 100644 index 0000000..885625e --- /dev/null +++ b/go/wordy/wordy_test.go @@ -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) + } + } +}