Initial Commit
This commit is contained in:
39
go/allergies/README.md
Normal file
39
go/allergies/README.md
Normal file
@@ -0,0 +1,39 @@
|
||||
# Allergies
|
||||
|
||||
Write a program that, given a person's allergy score, can tell them whether or not they're allergic to a given item, and their full list of allergies.
|
||||
|
||||
An allergy test produces a single numeric score which contains the
|
||||
information about all the allergies the person has (that they were
|
||||
tested for).
|
||||
|
||||
The list of items (and their value) that were tested are:
|
||||
|
||||
* eggs (1)
|
||||
* peanuts (2)
|
||||
* shellfish (4)
|
||||
* strawberries (8)
|
||||
* tomatoes (16)
|
||||
* chocolate (32)
|
||||
* pollen (64)
|
||||
* cats (128)
|
||||
|
||||
So if Tom is allergic to peanuts and chocolate, he gets a score of 34.
|
||||
|
||||
Now, given just that score of 34, your program should be able to say:
|
||||
|
||||
- Whether Tom is allergic to any one of those allergens listed above.
|
||||
- All the allergens Tom is allergic to.
|
||||
|
||||
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
|
||||
|
||||
Jumpstart Lab Warm-up [view source](http://jumpstartlab.com)
|
44
go/allergies/allergies.go
Normal file
44
go/allergies/allergies.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package allergies
|
||||
|
||||
// Allergies takes a score and returns all of the
|
||||
// things that the score is allergic to.
|
||||
func Allergies(score int) []string {
|
||||
var ret []string
|
||||
|
||||
for _, v := range getAllAllergens() {
|
||||
if AllergicTo(score, v) {
|
||||
ret = append(ret, v)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// AllergicTo takes a score and an allergen and returns if
|
||||
// That score is allergic to that thing.
|
||||
func AllergicTo(score int, tst string) bool {
|
||||
return score&getScoreForAllergen(tst) == getScoreForAllergen(tst)
|
||||
}
|
||||
|
||||
func getAllAllergens() []string {
|
||||
return []string{
|
||||
"eggs",
|
||||
"peanuts",
|
||||
"shellfish",
|
||||
"strawberries",
|
||||
"tomatoes",
|
||||
"chocolate",
|
||||
"pollen",
|
||||
"cats",
|
||||
}
|
||||
}
|
||||
|
||||
func getScoreForAllergen(tst string) int {
|
||||
ret := 1
|
||||
for _, v := range getAllAllergens() {
|
||||
if tst == v {
|
||||
return ret
|
||||
}
|
||||
ret *= 2
|
||||
}
|
||||
return -1
|
||||
}
|
79
go/allergies/allergies_test.go
Normal file
79
go/allergies/allergies_test.go
Normal file
@@ -0,0 +1,79 @@
|
||||
package allergies
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var allergiesTests = []struct {
|
||||
expected []string
|
||||
input int
|
||||
}{
|
||||
{[]string{}, 0},
|
||||
{[]string{"eggs"}, 1},
|
||||
{[]string{"peanuts"}, 2},
|
||||
{[]string{"strawberries"}, 8},
|
||||
{[]string{"eggs", "peanuts"}, 3},
|
||||
{[]string{"eggs", "shellfish"}, 5},
|
||||
{[]string{"strawberries", "tomatoes", "chocolate", "pollen", "cats"}, 248},
|
||||
{[]string{"eggs", "peanuts", "shellfish", "strawberries", "tomatoes", "chocolate", "pollen", "cats"}, 255},
|
||||
{[]string{"eggs", "shellfish", "strawberries", "tomatoes", "chocolate", "pollen", "cats"}, 509},
|
||||
}
|
||||
|
||||
func TestAllergies(t *testing.T) {
|
||||
for _, test := range allergiesTests {
|
||||
actual := Allergies(test.input)
|
||||
if fmt.Sprintf("%s", actual) != fmt.Sprintf("%s", test.expected) {
|
||||
t.Fatalf("FAIL: Allergies(%d): expected %s, actual %s", test.input, test.expected, actual)
|
||||
} else {
|
||||
t.Logf("PASS: Allergic to %v", test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAllergies(b *testing.B) {
|
||||
b.StopTimer()
|
||||
for _, test := range allergicToTests {
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
Allergies(test.i)
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
}
|
||||
|
||||
var allergicToTests = []struct {
|
||||
expected bool
|
||||
i int
|
||||
allergen string
|
||||
}{
|
||||
{false, 0, "peanuts"},
|
||||
{false, 0, "cats"},
|
||||
{false, 0, "strawberries"},
|
||||
{true, 1, "eggs"},
|
||||
{true, 5, "eggs"},
|
||||
}
|
||||
|
||||
func TestAllergicTo(t *testing.T) {
|
||||
for _, test := range allergicToTests {
|
||||
actual := AllergicTo(test.i, test.allergen)
|
||||
if actual != test.expected {
|
||||
t.Fatalf("FAIL: AllergicTo(%d, %s): expected %t, actual %t", test.i, test.allergen, test.expected, actual)
|
||||
} else {
|
||||
t.Logf("PASS: AllergicTo(%d, %s) %t", test.i, test.allergen, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAllergicTo(b *testing.B) {
|
||||
b.StopTimer()
|
||||
for _, test := range allergicToTests {
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
AllergicTo(test.i, test.allergen)
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
}
|
21
go/anagram/README.md
Normal file
21
go/anagram/README.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# Anagram
|
||||
|
||||
Write a program that, given a word and a list of possible anagrams, selects the correct sublist.
|
||||
|
||||
Given `"listen"` and a list of candidates like `"enlists" "google"
|
||||
"inlets" "banana"` the program should return a list containing
|
||||
`"inlets"`.
|
||||
|
||||
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 Extreme Startup game [view source](https://github.com/rchatley/extreme_startup)
|
28
go/anagram/anagram.go
Normal file
28
go/anagram/anagram.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package anagram
|
||||
|
||||
import "strings"
|
||||
|
||||
// Detect returns all candidates that are anagrams of subject
|
||||
func Detect(subject string, candidates []string) []string {
|
||||
var ret []string
|
||||
for i := range candidates {
|
||||
if isAnagram(subject, candidates[i]) {
|
||||
ret = append(ret, strings.ToLower(candidates[i]))
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func isAnagram(s, c string) bool {
|
||||
s = strings.ToLower(s)
|
||||
c = strings.ToLower(c)
|
||||
if s == c || len(s) != len(c) {
|
||||
return false
|
||||
}
|
||||
for _, v := range strings.Split(s, "") {
|
||||
if strings.Count(s, v) != strings.Count(c, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
172
go/anagram/anagram_test.go
Normal file
172
go/anagram/anagram_test.go
Normal file
@@ -0,0 +1,172 @@
|
||||
package anagram
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testCases = []struct {
|
||||
subject string
|
||||
candidates []string
|
||||
expected []string
|
||||
description string
|
||||
}{
|
||||
{
|
||||
subject: "diaper",
|
||||
candidates: []string{
|
||||
"hello",
|
||||
"world",
|
||||
"zombies",
|
||||
"pants",
|
||||
},
|
||||
expected: []string{},
|
||||
description: "no matches",
|
||||
},
|
||||
{
|
||||
subject: "ant",
|
||||
candidates: []string{
|
||||
"tan",
|
||||
"stand",
|
||||
"at",
|
||||
},
|
||||
expected: []string{"tan"},
|
||||
description: "simple anagram",
|
||||
},
|
||||
{
|
||||
subject: "listen",
|
||||
candidates: []string{
|
||||
"enlists",
|
||||
"google",
|
||||
"inlets",
|
||||
"banana",
|
||||
},
|
||||
expected: []string{"inlets"},
|
||||
description: "another simple anagram",
|
||||
},
|
||||
{
|
||||
subject: "master",
|
||||
candidates: []string{
|
||||
"stream",
|
||||
"pigeon",
|
||||
"maters",
|
||||
},
|
||||
expected: []string{"maters", "stream"},
|
||||
description: "multiple anagrams",
|
||||
},
|
||||
{
|
||||
subject: "allergy",
|
||||
candidates: []string{
|
||||
"gallery",
|
||||
"ballerina",
|
||||
"regally",
|
||||
"clergy",
|
||||
"largely",
|
||||
"leading",
|
||||
},
|
||||
expected: []string{"gallery", "largely", "regally"},
|
||||
description: "multiple anagrams (again)",
|
||||
},
|
||||
{
|
||||
subject: "galea",
|
||||
candidates: []string{
|
||||
"eagle",
|
||||
},
|
||||
expected: []string{},
|
||||
description: "does not confuse different duplicates",
|
||||
},
|
||||
{
|
||||
subject: "corn",
|
||||
candidates: []string{
|
||||
"corn",
|
||||
"dark",
|
||||
"Corn",
|
||||
"rank",
|
||||
"CORN",
|
||||
"cron",
|
||||
"park",
|
||||
},
|
||||
expected: []string{"cron"},
|
||||
description: "identical word is not anagram",
|
||||
},
|
||||
{
|
||||
subject: "mass",
|
||||
candidates: []string{
|
||||
"last",
|
||||
},
|
||||
expected: []string{},
|
||||
description: "eliminate anagrams with same checksum",
|
||||
},
|
||||
{
|
||||
subject: "good",
|
||||
candidates: []string{
|
||||
"dog",
|
||||
"goody",
|
||||
},
|
||||
expected: []string{},
|
||||
description: "eliminate anagram subsets",
|
||||
},
|
||||
{
|
||||
subject: "Orchestra",
|
||||
candidates: []string{
|
||||
"cashregiser",
|
||||
"carthorse",
|
||||
"radishes",
|
||||
},
|
||||
expected: []string{"carthorse"},
|
||||
description: "subjects are case insensitive",
|
||||
},
|
||||
{
|
||||
subject: "orchestra",
|
||||
candidates: []string{
|
||||
"cashregiser",
|
||||
"Carthorse",
|
||||
"radishes",
|
||||
},
|
||||
expected: []string{"carthorse"},
|
||||
description: "candidates are case insensitive",
|
||||
},
|
||||
}
|
||||
|
||||
func equal(a []string, b []string) bool {
|
||||
if len(b) != len(a) {
|
||||
return false
|
||||
}
|
||||
|
||||
sort.Strings(a)
|
||||
sort.Strings(b)
|
||||
return fmt.Sprintf("%v", a) == fmt.Sprintf("%v", b)
|
||||
}
|
||||
|
||||
func TestDetectAnagrams(t *testing.T) {
|
||||
for _, tt := range testCases {
|
||||
actual := Detect(tt.subject, tt.candidates)
|
||||
if !equal(tt.expected, actual) {
|
||||
msg := `FAIL: %s
|
||||
Subject %s
|
||||
Candidates %v
|
||||
Expected %v
|
||||
Got %v
|
||||
`
|
||||
t.Fatalf(msg, tt.description, tt.subject, tt.candidates, tt.expected, actual)
|
||||
} else {
|
||||
t.Logf("PASS: %s", tt.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDetectAnagrams(b *testing.B) {
|
||||
|
||||
b.StopTimer()
|
||||
|
||||
for _, tt := range testCases {
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
Detect(tt.subject, tt.candidates)
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
}
|
40
go/bank-account/README.md
Normal file
40
go/bank-account/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Bank Account
|
||||
|
||||
Bank accounts can be accessed in different ways at the same time.
|
||||
|
||||
A bank account can be accessed in multiple ways. Clients can make
|
||||
deposits and withdrawals using the internet, mobile phones, etc. Shops
|
||||
can charge against the account.
|
||||
|
||||
Create an account that can be accessed from multiple threads/processes
|
||||
(terminology depends on your programming language).
|
||||
|
||||
It should be possible to close an account; operations against a closed
|
||||
account must fail.
|
||||
|
||||
## Instructions
|
||||
|
||||
Run the test file, and fix each of the errors in turn. When you get the
|
||||
first test to pass, go to the first pending or skipped test, and make
|
||||
that pass as well. When all of the tests are passing, feel free to
|
||||
submit.
|
||||
|
||||
Remember that passing code is just the first step. The goal is to work
|
||||
towards a solution that is as readable and expressive as you can make
|
||||
it.
|
||||
|
||||
Have fun!
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
[view source]()
|
58
go/bank-account/account.go
Normal file
58
go/bank-account/account.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package account
|
||||
|
||||
import "sync"
|
||||
|
||||
// Account just represents a user's account
|
||||
type Account struct {
|
||||
sync.RWMutex
|
||||
balance int
|
||||
closed bool
|
||||
}
|
||||
|
||||
// Open returns a new account
|
||||
func Open(amt int) *Account {
|
||||
a := new(Account)
|
||||
_, ok := a.Deposit(amt)
|
||||
if ok {
|
||||
return a
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Close returns the payout amount and an 'ok' flag
|
||||
func (a *Account) Close() (int, bool) {
|
||||
a.Lock()
|
||||
ret := a.balance
|
||||
if a.closed {
|
||||
a.Unlock()
|
||||
return 0, false
|
||||
}
|
||||
a.closed = true
|
||||
a.balance = 0
|
||||
a.Unlock()
|
||||
return ret, true
|
||||
}
|
||||
|
||||
// Balance returns the current account balance
|
||||
// and an 'ok' flag
|
||||
func (a *Account) Balance() (int, bool) {
|
||||
if a.closed {
|
||||
return 0, false
|
||||
}
|
||||
return a.balance, true
|
||||
}
|
||||
|
||||
// Deposit takes an amount (can be a withdrawal)
|
||||
// and returns the new balance and an 'ok' flag
|
||||
func (a *Account) Deposit(amount int) (int, bool) {
|
||||
var ret int
|
||||
var ok bool
|
||||
a.Lock()
|
||||
if !a.closed && a.balance+amount >= 0 {
|
||||
a.balance += amount
|
||||
ret = a.balance
|
||||
ok = true
|
||||
}
|
||||
a.Unlock()
|
||||
return ret, ok
|
||||
}
|
289
go/bank-account/bank_account_test.go
Normal file
289
go/bank-account/bank_account_test.go
Normal file
@@ -0,0 +1,289 @@
|
||||
// API:
|
||||
//
|
||||
// Open(initalDeposit int64) *Account
|
||||
// (Account) Close() (payout int64, ok bool)
|
||||
// (Account) Balance() (balance int64, ok bool)
|
||||
// (Account) Deposit(amount uint64) (newBalance int64, ok bool)
|
||||
//
|
||||
// If Open is given a negative initial deposit, it must return nil.
|
||||
// Deposit must handle a negative amount as a withdrawal.
|
||||
// If any Account method is called on an closed account, it must not modify
|
||||
// the account and must return ok = false.
|
||||
|
||||
package account
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"sync"
|
||||
"sync/atomic"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSeqOpenBalanceClose(t *testing.T) {
|
||||
// open account
|
||||
const amt = 10
|
||||
a := Open(amt)
|
||||
if a == nil {
|
||||
t.Fatalf("Open(%d) = nil, want non-nil *Account.", amt)
|
||||
}
|
||||
t.Logf("Account 'a' opened with initial balance of %d.", amt)
|
||||
|
||||
// verify balance after open
|
||||
switch b, ok := a.Balance(); {
|
||||
case !ok:
|
||||
t.Fatal("a.Balance() returned !ok, want ok.")
|
||||
case b != amt:
|
||||
t.Fatalf("a.Balance() = %d, want %d", b, amt)
|
||||
}
|
||||
|
||||
// close account
|
||||
switch p, ok := a.Close(); {
|
||||
case !ok:
|
||||
t.Fatalf("a.Close() returned !ok, want ok.")
|
||||
case p != amt:
|
||||
t.Fatalf("a.Close() returned payout = %d, want %d.", p, amt)
|
||||
}
|
||||
t.Log("Account 'a' closed.")
|
||||
|
||||
// verify balance no longer accessible
|
||||
if b, ok := a.Balance(); ok {
|
||||
t.Log("Balance still available on closed account.")
|
||||
t.Fatalf("a.Balance() = %d, %t. Want ok == false", b, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSeqOpenDepositClose(t *testing.T) {
|
||||
// open account
|
||||
const openAmt = 10
|
||||
a := Open(openAmt)
|
||||
if a == nil {
|
||||
t.Fatalf("Open(%d) = nil, want non-nil *Account.", openAmt)
|
||||
}
|
||||
t.Logf("Account 'a' opened with initial balance of %d.", openAmt)
|
||||
|
||||
// deposit
|
||||
const depAmt = 20
|
||||
const newAmt = openAmt + depAmt
|
||||
switch b, ok := a.Deposit(depAmt); {
|
||||
case !ok:
|
||||
t.Fatalf("a.Deposit(%d) returned !ok, want ok.", depAmt)
|
||||
case b != openAmt+depAmt:
|
||||
t.Fatalf("a.Deposit(%d) = %d, want new balance = %d", depAmt, b, newAmt)
|
||||
}
|
||||
t.Logf("Deposit of %d accepted to account 'a'", depAmt)
|
||||
|
||||
// close account
|
||||
switch p, ok := a.Close(); {
|
||||
case !ok:
|
||||
t.Fatalf("a.Close() returned !ok, want ok.")
|
||||
case p != newAmt:
|
||||
t.Fatalf("a.Close() returned payout = %d, want %d.", p, newAmt)
|
||||
}
|
||||
t.Log("Account 'a' closed.")
|
||||
|
||||
// verify deposits no longer accepted
|
||||
if b, ok := a.Deposit(1); ok {
|
||||
t.Log("Deposit accepted on closed account.")
|
||||
t.Fatalf("a.Deposit(1) = %d, %t. Want ok == false", b, ok)
|
||||
}
|
||||
}
|
||||
|
||||
func TestMoreSeqCases(t *testing.T) {
|
||||
// open account 'a' as before
|
||||
const openAmt = 10
|
||||
a := Open(openAmt)
|
||||
if a == nil {
|
||||
t.Fatalf("Open(%d) = nil, want non-nil *Account.", openAmt)
|
||||
}
|
||||
t.Logf("Account 'a' opened with initial balance of %d.", openAmt)
|
||||
|
||||
// open account 'z' with zero balance
|
||||
z := Open(0)
|
||||
if z == nil {
|
||||
t.Fatal("Open(0) = nil, want non-nil *Account.")
|
||||
}
|
||||
t.Log("Account 'z' opened with initial balance of 0.")
|
||||
|
||||
// attempt to open account with negative opening balance
|
||||
if Open(-10) != nil {
|
||||
t.Fatal("Open(-10) seemed to work, " +
|
||||
"want nil result for negative opening balance.")
|
||||
}
|
||||
|
||||
// verify both balances a and z still there
|
||||
switch b, ok := a.Balance(); {
|
||||
case !ok:
|
||||
t.Fatal("a.Balance() returned !ok, want ok.")
|
||||
case b != openAmt:
|
||||
t.Fatalf("a.Balance() = %d, want %d", b, openAmt)
|
||||
}
|
||||
switch b, ok := z.Balance(); {
|
||||
case !ok:
|
||||
t.Fatal("z.Balance() returned !ok, want ok.")
|
||||
case b != 0:
|
||||
t.Fatalf("z.Balance() = %d, want 0", b)
|
||||
}
|
||||
|
||||
// withdrawals
|
||||
const wAmt = 3
|
||||
const newAmt = openAmt - wAmt
|
||||
switch b, ok := a.Deposit(-wAmt); {
|
||||
case !ok:
|
||||
t.Fatalf("a.Deposit(%d) returned !ok, want ok.", -wAmt)
|
||||
case b != newAmt:
|
||||
t.Fatalf("a.Deposit(%d) = %d, want new balance = %d", -wAmt, b, newAmt)
|
||||
}
|
||||
t.Logf("Withdrawal of %d accepted from account 'a'", wAmt)
|
||||
if _, ok := z.Deposit(-1); ok {
|
||||
t.Fatal("z.Deposit(-1) returned ok, want !ok.")
|
||||
}
|
||||
|
||||
// verify both balances
|
||||
switch b, ok := a.Balance(); {
|
||||
case !ok:
|
||||
t.Fatal("a.Balance() returned !ok, want ok.")
|
||||
case b != newAmt:
|
||||
t.Fatalf("a.Balance() = %d, want %d", b, newAmt)
|
||||
}
|
||||
switch b, ok := z.Balance(); {
|
||||
case !ok:
|
||||
t.Fatal("z.Balance() returned !ok, want ok.")
|
||||
case b != 0:
|
||||
t.Fatalf("z.Balance() = %d, want 0", b)
|
||||
}
|
||||
|
||||
// close just z
|
||||
switch p, ok := z.Close(); {
|
||||
case !ok:
|
||||
t.Fatalf("z.Close() returned !ok, want ok.")
|
||||
case p != 0:
|
||||
t.Fatalf("z.Close() returned payout = %d, want 0.", p)
|
||||
}
|
||||
t.Log("Account 'z' closed.")
|
||||
|
||||
// verify 'a' balance one more time
|
||||
switch b, ok := a.Balance(); {
|
||||
case !ok:
|
||||
t.Fatal("a.Balance() returned !ok, want ok.")
|
||||
case b != newAmt:
|
||||
t.Fatalf("a.Balance() = %d, want %d", b, newAmt)
|
||||
}
|
||||
}
|
||||
|
||||
func TestConcClose(t *testing.T) {
|
||||
if runtime.NumCPU() < 2 {
|
||||
t.Skip("Multiple CPU cores required for concurrency tests.")
|
||||
}
|
||||
if runtime.GOMAXPROCS(0) < 2 {
|
||||
runtime.GOMAXPROCS(2)
|
||||
}
|
||||
|
||||
// test competing close attempts
|
||||
for rep := 0; rep < 1000; rep++ {
|
||||
const openAmt = 10
|
||||
a := Open(openAmt)
|
||||
if a == nil {
|
||||
t.Fatalf("Open(%d) = nil, want non-nil *Account.", openAmt)
|
||||
}
|
||||
var start sync.WaitGroup
|
||||
start.Add(1)
|
||||
const closeAttempts = 10
|
||||
res := make(chan string)
|
||||
for i := 0; i < closeAttempts; i++ {
|
||||
go func() { // on your mark,
|
||||
start.Wait() // get set...
|
||||
switch p, ok := a.Close(); {
|
||||
case !ok:
|
||||
if p != 0 {
|
||||
t.Errorf("a.Close() = %d, %t. "+
|
||||
"Want payout = 0 for unsuccessful close", p, ok)
|
||||
res <- "fail"
|
||||
} else {
|
||||
res <- "already closed"
|
||||
}
|
||||
case p != openAmt:
|
||||
t.Errorf("a.Close() = %d, %t. "+
|
||||
"Want payout = %d for successful close", p, ok, openAmt)
|
||||
res <- "fail"
|
||||
default:
|
||||
res <- "close" // exactly one goroutine should reach here
|
||||
}
|
||||
}()
|
||||
}
|
||||
start.Done() // ...go
|
||||
var closes, fails int
|
||||
for i := 0; i < closeAttempts; i++ {
|
||||
switch <-res {
|
||||
case "close":
|
||||
closes++
|
||||
case "fail":
|
||||
fails++
|
||||
}
|
||||
}
|
||||
switch {
|
||||
case fails > 0:
|
||||
t.FailNow() // error already logged by other goroutine
|
||||
case closes == 0:
|
||||
t.Fatal("Concurrent a.Close() attempts all failed. " +
|
||||
"Want one to succeed.")
|
||||
case closes > 1:
|
||||
t.Fatalf("%d concurrent a.Close() attempts succeeded, "+
|
||||
"each paying out %d!. Want just one to succeed.",
|
||||
closes, openAmt)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestConcDeposit(t *testing.T) {
|
||||
if runtime.NumCPU() < 2 {
|
||||
t.Skip("Multiple CPU cores required for concurrency tests.")
|
||||
}
|
||||
if runtime.GOMAXPROCS(0) < 2 {
|
||||
runtime.GOMAXPROCS(2)
|
||||
}
|
||||
a := Open(0)
|
||||
if a == nil {
|
||||
t.Fatal("Open(0) = nil, want non-nil *Account.")
|
||||
}
|
||||
const amt = 10
|
||||
const c = 1000
|
||||
var negBal int32
|
||||
var start, g sync.WaitGroup
|
||||
start.Add(1)
|
||||
g.Add(3 * c)
|
||||
for i := 0; i < c; i++ {
|
||||
go func() { // deposit
|
||||
start.Wait()
|
||||
a.Deposit(amt) // ignore return values
|
||||
g.Done()
|
||||
}()
|
||||
go func() { // withdraw
|
||||
start.Wait()
|
||||
for {
|
||||
if _, ok := a.Deposit(-amt); ok {
|
||||
break
|
||||
}
|
||||
time.Sleep(time.Microsecond) // retry
|
||||
}
|
||||
g.Done()
|
||||
}()
|
||||
go func() { // watch that balance stays >= 0
|
||||
start.Wait()
|
||||
if p, _ := a.Balance(); p < 0 {
|
||||
atomic.StoreInt32(&negBal, 1)
|
||||
}
|
||||
g.Done()
|
||||
}()
|
||||
}
|
||||
start.Done()
|
||||
g.Wait()
|
||||
if negBal == 1 {
|
||||
t.Fatal("Balance went negative with concurrent deposits and " +
|
||||
"withdrawals. Want balance always >= 0.")
|
||||
}
|
||||
if p, ok := a.Balance(); !ok || p != 0 {
|
||||
t.Fatalf("After equal concurrent deposits and withdrawals, "+
|
||||
"a.Balance = %d, %t. Want 0, true", p, ok)
|
||||
}
|
||||
}
|
43
go/binary/README.md
Normal file
43
go/binary/README.md
Normal file
@@ -0,0 +1,43 @@
|
||||
# Binary
|
||||
|
||||
Write a program that will convert a binary number, represented as a string (e.g. '101010'), to its decimal equivalent using first principles
|
||||
|
||||
Implement binary to decimal conversion. Given a binary input
|
||||
string, your program should produce a decimal output. The
|
||||
program should handle invalid inputs.
|
||||
|
||||
## Note
|
||||
- Implement the conversion yourself.
|
||||
Do not use something else to perform the conversion for you.
|
||||
|
||||
## About Binary (Base-2)
|
||||
Decimal is a base-10 system.
|
||||
|
||||
A number 23 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: `23 => 2*10^1 + 3*10^0 => 2*10 + 3*1 = 23 base 10`
|
||||
|
||||
Binary is similar, but uses powers of 2 rather than powers of 10.
|
||||
|
||||
So: `101 => 1*2^2 + 0*2^1 + 1*2^0 => 1*4 + 0*2 + 1*1 => 4 + 1 => 5 base 10`.
|
||||
|
||||
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 [view source](http://www.wolframalpha.com/input/?i=binary&a=*C.binary-_*MathWorld-)
|
22
go/binary/binary.go
Normal file
22
go/binary/binary.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package binary
|
||||
|
||||
import "fmt"
|
||||
|
||||
// ParseBinary takes a binary string and returns the
|
||||
// integer representation of it.
|
||||
func ParseBinary(bin string) (int, error) {
|
||||
var ret int
|
||||
currSpot := 1
|
||||
for len(bin) > 0 {
|
||||
v := bin[len(bin)-1]
|
||||
if v != '0' && v != '1' {
|
||||
return 0, fmt.Errorf("Invalid String")
|
||||
}
|
||||
if v == '1' {
|
||||
ret = ret + currSpot
|
||||
}
|
||||
currSpot = currSpot * 2
|
||||
bin = bin[:len(bin)-1]
|
||||
}
|
||||
return ret, nil
|
||||
}
|
55
go/binary/binary_test.go
Normal file
55
go/binary/binary_test.go
Normal file
@@ -0,0 +1,55 @@
|
||||
package binary
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
// You must implement the function,
|
||||
//
|
||||
// func ParseBinary(string) (int, error)
|
||||
//
|
||||
// It is standard for Go functions to return error values to report error conditions.
|
||||
// The test cases below are all valid binary numbers however. For this exercise you
|
||||
// may simply return nil for the error value in all cases.
|
||||
//
|
||||
// For bonus points though, what errors might be possible when parsing a number?
|
||||
// Can you add code to detect error conditions and return appropriate error values?
|
||||
|
||||
var testCases = []struct {
|
||||
binary string
|
||||
expected int
|
||||
}{
|
||||
{"1", 1},
|
||||
{"10", 2},
|
||||
{"11", 3},
|
||||
{"100", 4},
|
||||
{"1001", 9},
|
||||
{"11010", 26},
|
||||
{"10001101000", 1128},
|
||||
{"0", 0},
|
||||
}
|
||||
|
||||
func TestParseBinary(t *testing.T) {
|
||||
for _, tt := range testCases {
|
||||
actual, err := ParseBinary(tt.binary)
|
||||
// We don't expect errors for any of the test cases.
|
||||
if err != nil {
|
||||
t.Fatalf("ParseBinary(%v) returned error %q. Error not expected.",
|
||||
tt.binary, err)
|
||||
}
|
||||
// Well, we don't expect wrong answers either.
|
||||
if actual != tt.expected {
|
||||
t.Fatalf("ParseBinary(%v): actual %d, expected %v",
|
||||
tt.binary, actual, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark combined time for all tests
|
||||
func BenchmarkBinary(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, tt := range testCases {
|
||||
ParseBinary(tt.binary)
|
||||
}
|
||||
}
|
||||
}
|
44
go/bob/README.md
Normal file
44
go/bob/README.md
Normal file
@@ -0,0 +1,44 @@
|
||||
# Bob
|
||||
|
||||
Bob is a lackadaisical teenager. In conversation, his responses are very limited.
|
||||
|
||||
Bob answers 'Sure.' if you ask him a question.
|
||||
|
||||
He answers 'Whoa, chill out!' if you yell at him.
|
||||
|
||||
He says 'Fine. Be that way!' if you address him without actually saying
|
||||
anything.
|
||||
|
||||
He answers 'Whatever.' to anything else.
|
||||
|
||||
## Instructions
|
||||
|
||||
Run the test file, and fix each of the errors in turn. When you get the
|
||||
first test to pass, go to the first pending or skipped test, and make
|
||||
that pass as well. When all of the tests are passing, feel free to
|
||||
submit.
|
||||
|
||||
Remember that passing code is just the first step. The goal is to work
|
||||
towards a solution that is as readable and expressive as you can make
|
||||
it.
|
||||
|
||||
Please make your solution as general as possible. Good code doesn't just
|
||||
pass the test suite, it works with any input that fits the
|
||||
specification.
|
||||
|
||||
Have fun!
|
||||
|
||||
|
||||
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 'Deaf Grandma' exercise in Chris Pine's Learn to Program tutorial. [view source](http://pine.fm/LearnToProgram/?Chapter=06)
|
19
go/bob/bob.go
Normal file
19
go/bob/bob.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package bob
|
||||
|
||||
import "strings"
|
||||
|
||||
// TestVersion is an exercism thing
|
||||
const TestVersion = 1
|
||||
|
||||
// Hey provokes a response from Bob
|
||||
func Hey(inp string) string {
|
||||
inp = strings.TrimSpace(inp)
|
||||
if inp == "" {
|
||||
return "Fine. Be that way!"
|
||||
} else if inp == strings.ToUpper(inp) && inp != strings.ToLower(inp) {
|
||||
return "Whoa, chill out!"
|
||||
} else if strings.HasSuffix(inp, "?") {
|
||||
return "Sure."
|
||||
}
|
||||
return "Whatever."
|
||||
}
|
33
go/bob/bob_test.go
Normal file
33
go/bob/bob_test.go
Normal file
@@ -0,0 +1,33 @@
|
||||
package bob
|
||||
|
||||
import "testing"
|
||||
|
||||
const testVersion = 1
|
||||
|
||||
// Retired testVersions
|
||||
// (none) 4a9e144a3c5dc0d9773f4cf641ffe3efe48641d8
|
||||
|
||||
func TestHeyBob(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion)
|
||||
}
|
||||
for _, tt := range testCases {
|
||||
actual := Hey(tt.input)
|
||||
if actual != tt.expected {
|
||||
msg := `
|
||||
ALICE (%s): %q
|
||||
BOB: %s
|
||||
|
||||
Expected Bob to respond: %s`
|
||||
t.Fatalf(msg, tt.description, tt.input, actual, tt.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBob(b *testing.B) {
|
||||
for _, tt := range testCases {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Hey(tt.input)
|
||||
}
|
||||
}
|
||||
}
|
141
go/bob/cases_test.go
Normal file
141
go/bob/cases_test.go
Normal file
@@ -0,0 +1,141 @@
|
||||
package bob
|
||||
|
||||
// Source: exercism/x-common
|
||||
// Commit: 945d08e Merge pull request #50 from soniakeys/master
|
||||
|
||||
var testCases = []struct {
|
||||
description string
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
"stating something",
|
||||
"Tom-ay-to, tom-aaaah-to.",
|
||||
"Whatever.",
|
||||
},
|
||||
{
|
||||
"shouting",
|
||||
"WATCH OUT!",
|
||||
"Whoa, chill out!",
|
||||
},
|
||||
{
|
||||
"shouting gibberish",
|
||||
"FCECDFCAAB",
|
||||
"Whoa, chill out!",
|
||||
},
|
||||
{
|
||||
"asking a question",
|
||||
"Does this cryogenic chamber make me look fat?",
|
||||
"Sure.",
|
||||
},
|
||||
{
|
||||
"asking a numeric question",
|
||||
"You are, what, like 15?",
|
||||
"Sure.",
|
||||
},
|
||||
{
|
||||
"asking gibberish",
|
||||
"fffbbcbeab?",
|
||||
"Sure.",
|
||||
},
|
||||
{
|
||||
"talking forcefully",
|
||||
"Let's go make out behind the gym!",
|
||||
"Whatever.",
|
||||
},
|
||||
{
|
||||
"using acronyms in regular speech",
|
||||
"It's OK if you don't want to go to the DMV.",
|
||||
"Whatever.",
|
||||
},
|
||||
{
|
||||
"forceful question",
|
||||
"WHAT THE HELL WERE YOU THINKING?",
|
||||
"Whoa, chill out!",
|
||||
},
|
||||
{
|
||||
"shouting numbers",
|
||||
"1, 2, 3 GO!",
|
||||
"Whoa, chill out!",
|
||||
},
|
||||
{
|
||||
"only numbers",
|
||||
"1, 2, 3",
|
||||
"Whatever.",
|
||||
},
|
||||
{
|
||||
"question with only numbers",
|
||||
"4?",
|
||||
"Sure.",
|
||||
},
|
||||
{
|
||||
"shouting with special characters",
|
||||
"ZOMG THE %^*@#$(*^ ZOMBIES ARE COMING!!11!!1!",
|
||||
"Whoa, chill out!",
|
||||
},
|
||||
{
|
||||
"shouting with umlauts",
|
||||
"ÜMLÄÜTS!",
|
||||
"Whoa, chill out!",
|
||||
},
|
||||
{
|
||||
"calmly speaking with umlauts",
|
||||
"ÜMLäÜTS!",
|
||||
"Whatever.",
|
||||
},
|
||||
{
|
||||
"shouting with no exclamation mark",
|
||||
"I HATE YOU",
|
||||
"Whoa, chill out!",
|
||||
},
|
||||
{
|
||||
"statement containing question mark",
|
||||
"Ending with ? means a question.",
|
||||
"Whatever.",
|
||||
},
|
||||
{
|
||||
"non-letters with question",
|
||||
":) ?",
|
||||
"Sure.",
|
||||
},
|
||||
{
|
||||
"prattling on",
|
||||
"Wait! Hang on. Are you going to be OK?",
|
||||
"Sure.",
|
||||
},
|
||||
{
|
||||
"silence",
|
||||
"",
|
||||
"Fine. Be that way!",
|
||||
},
|
||||
{
|
||||
"prolonged silence",
|
||||
" ",
|
||||
"Fine. Be that way!",
|
||||
},
|
||||
{
|
||||
"alternate silence",
|
||||
"\t\t\t\t\t\t\t\t\t\t",
|
||||
"Fine. Be that way!",
|
||||
},
|
||||
{
|
||||
"multiple line question",
|
||||
"\nDoes this cryogenic chamber make me look fat?\nno",
|
||||
"Whatever.",
|
||||
},
|
||||
{
|
||||
"starting with whitespace",
|
||||
" hmmmmmmm...",
|
||||
"Whatever.",
|
||||
},
|
||||
{
|
||||
"ending with whitespace",
|
||||
"Okay if like my spacebar quite a bit? ",
|
||||
"Sure.",
|
||||
},
|
||||
{
|
||||
"other whitespace",
|
||||
"\n\r \t\v\u00a0\u2002",
|
||||
"Fine. Be that way!",
|
||||
},
|
||||
}
|
20
go/bracket-push/README.md
Normal file
20
go/bracket-push/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Bracket Push
|
||||
|
||||
Make sure the brackets and braces all match.
|
||||
|
||||
Ensure that all the brackets and braces are matched correctly,
|
||||
and nested correctly.
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
Ginna Baker [view source]()
|
26
go/bracket-push/bracket-push.go
Normal file
26
go/bracket-push/bracket-push.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package bracket_push
|
||||
|
||||
// Bracket makes sure that all brackets match
|
||||
func Bracket(s string) (bool, error) {
|
||||
// Set up a map of matches that we care about
|
||||
matches := make(map[byte]byte)
|
||||
matches['}'] = '{'
|
||||
matches[')'] = '('
|
||||
matches[']'] = '['
|
||||
var pairs []byte
|
||||
for i := range s {
|
||||
if v, ok := matches[s[i]]; ok {
|
||||
// Found a match, it's a closing bracket
|
||||
if len(pairs) == 0 || pairs[len(pairs)-1] != v {
|
||||
return false, nil
|
||||
}
|
||||
pairs = pairs[:len(pairs)-1]
|
||||
} else {
|
||||
pairs = append(pairs, s[i])
|
||||
}
|
||||
}
|
||||
if len(pairs) > 0 {
|
||||
return false, nil
|
||||
}
|
||||
return true, nil
|
||||
}
|
72
go/bracket-push/bracket-push_test.go
Normal file
72
go/bracket-push/bracket-push_test.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package bracket_push
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var testCases = []struct {
|
||||
input string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
input: "",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
input: "{}",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
input: "{{",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
input: "}{",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
input: "{}[]",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
input: "{[]}",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
input: "{[}]",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
input: "{[)][]}",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
input: "{[]([()])}",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
func TestBracket(t *testing.T) {
|
||||
for _, tt := range testCases {
|
||||
actual, err := Bracket(tt.input)
|
||||
// We don't expect errors for any of the test cases
|
||||
if err != nil {
|
||||
t.Fatalf("Bracket(%q) returned error %q. Error not expected.", tt.input, err)
|
||||
}
|
||||
if actual != tt.expected {
|
||||
t.Fatalf("Bracket(%q) was expected to return %v but returned %v.",
|
||||
tt.input, tt.expected, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBracket(b *testing.B) {
|
||||
b.StopTimer()
|
||||
for _, tt := range testCases {
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Bracket(tt.input)
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
}
|
77
go/bracket-push/bracket_push_test.go
Normal file
77
go/bracket-push/bracket_push_test.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package brackets
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
const testVersion = 2
|
||||
|
||||
var testCases = []struct {
|
||||
input string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
input: "",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
input: "{}",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
input: "{{",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
input: "}{",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
input: "{}[]",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
input: "{[]}",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
input: "{[}]",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
input: "{[)][]}",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
input: "{[]([()])}",
|
||||
expected: true,
|
||||
},
|
||||
}
|
||||
|
||||
func TestBracket(t *testing.T) {
|
||||
for _, tt := range testCases {
|
||||
actual, err := Bracket(tt.input)
|
||||
// We don't expect errors for any of the test cases
|
||||
if err != nil {
|
||||
t.Fatalf("Bracket(%q) returned error %q. Error not expected.", tt.input, err)
|
||||
}
|
||||
if actual != tt.expected {
|
||||
t.Fatalf("Bracket(%q) was expected to return %v but returned %v.",
|
||||
tt.input, tt.expected, actual)
|
||||
}
|
||||
}
|
||||
if TestVersion != testVersion {
|
||||
t.Fatalf("Found TestVersion = %v, want %v.", TestVersion, testVersion)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkBracket(b *testing.B) {
|
||||
b.StopTimer()
|
||||
for _, tt := range testCases {
|
||||
b.StartTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
Bracket(tt.input)
|
||||
}
|
||||
b.StopTimer()
|
||||
}
|
||||
}
|
23
go/clock/README.md
Normal file
23
go/clock/README.md
Normal file
@@ -0,0 +1,23 @@
|
||||
# Clock
|
||||
|
||||
Implement a clock that handles times without dates.
|
||||
|
||||
Create a clock that is independent of date.
|
||||
|
||||
You should be able to add and subtract minutes to it.
|
||||
|
||||
Two clocks that represent the same time should be equal to each other.
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
Pairing session with Erin Drummond [view source](https://twitter.com/ebdrummond)
|
78
go/clock/cases_test.go
Normal file
78
go/clock/cases_test.go
Normal file
@@ -0,0 +1,78 @@
|
||||
package clock
|
||||
|
||||
// Source: exercism/x-common
|
||||
// Commit: 269f498 Merge pull request #48 from soniakeys/custom-set-json
|
||||
|
||||
// Test creating a new clock with an initial time.
|
||||
var timeTests = []struct {
|
||||
h, m int
|
||||
want string
|
||||
}{
|
||||
{8, 0, "08:00"}, // on the hour
|
||||
{9, 0, "09:00"}, // on the hour
|
||||
{11, 9, "11:09"}, // past the hour
|
||||
{11, 19, "11:19"}, // past the hour
|
||||
{24, 0, "00:00"}, // midnight is zero hours
|
||||
{25, 0, "01:00"}, // hour rolls over
|
||||
{1, 60, "02:00"}, // sixty minutes is next hour
|
||||
{0, 160, "02:40"}, // minutes roll over
|
||||
{25, 160, "03:40"}, // hour and minutes roll over
|
||||
{-1, 15, "23:15"}, // negative hour
|
||||
{-25, 0, "23:00"}, // negative hour rolls over
|
||||
{1, -40, "00:20"}, // negative minutes
|
||||
{1, -160, "22:20"}, // negative minutes roll over
|
||||
{-25, -160, "20:20"}, // negative hour and minutes both roll over
|
||||
}
|
||||
|
||||
// Test adding and subtracting minutes.
|
||||
var addTests = []struct {
|
||||
h, m, a int
|
||||
want string
|
||||
}{
|
||||
{10, 0, 3, "10:03"}, // add minutes
|
||||
{0, 45, 40, "01:25"}, // add to next hour
|
||||
{10, 0, 61, "11:01"}, // add more than one hour
|
||||
{23, 59, 2, "00:01"}, // add across midnight
|
||||
{5, 32, 1500, "06:32"}, // add more than one day (1500 min = 25 hrs)
|
||||
{0, 45, 160, "03:25"}, // add more than two hours with carry
|
||||
{10, 3, -3, "10:00"}, // subtract minutes
|
||||
{10, 3, -30, "09:33"}, // subtract to previous hour
|
||||
{10, 3, -70, "08:53"}, // subtract more than an hour
|
||||
{0, 3, -4, "23:59"}, // subtract across midnight
|
||||
{0, 0, -160, "21:20"}, // subtract more than two hours
|
||||
{5, 32, -1500, "04:32"}, // subtract more than one day (1500 min = 25 hrs)
|
||||
{6, 15, -160, "03:35"}, // subtract more than two hours with borrow
|
||||
}
|
||||
|
||||
// Construct two separate clocks, set times, test if they are equal.
|
||||
type hm struct{ h, m int }
|
||||
|
||||
var eqTests = []struct {
|
||||
c1, c2 hm
|
||||
want bool
|
||||
}{
|
||||
// clocks with same time
|
||||
{
|
||||
hm{15, 37},
|
||||
hm{15, 37},
|
||||
true,
|
||||
},
|
||||
// clocks a minute apart
|
||||
{
|
||||
hm{15, 36},
|
||||
hm{15, 37},
|
||||
false,
|
||||
},
|
||||
// clocks an hour apart
|
||||
{
|
||||
hm{14, 37},
|
||||
hm{15, 37},
|
||||
false,
|
||||
},
|
||||
// clocks set 24 hours apart
|
||||
{
|
||||
hm{10, 37},
|
||||
hm{34, 37},
|
||||
true,
|
||||
},
|
||||
}
|
34
go/clock/clock.go
Normal file
34
go/clock/clock.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package clock
|
||||
|
||||
import "fmt"
|
||||
|
||||
// TestVersion is for exercism
|
||||
const TestVersion = 2
|
||||
|
||||
// Clock is an int representing the time of day
|
||||
type Clock int
|
||||
|
||||
// Time returns a Clock representing the given hour & minute
|
||||
func Time(hour, minute int) Clock {
|
||||
return TimeFromMinutes(hour*60 + minute)
|
||||
}
|
||||
|
||||
// String returns a string representation of Clock
|
||||
func (c Clock) String() string {
|
||||
return fmt.Sprintf("%02d:%02d", c/60, c%60)
|
||||
}
|
||||
|
||||
// Add adds minutes to the clock
|
||||
func (c Clock) Add(minutes int) Clock {
|
||||
return TimeFromMinutes(int(c) + minutes)
|
||||
}
|
||||
|
||||
// TimeFromMinutes takes a minutes integer value and returns a Clock
|
||||
func TimeFromMinutes(minutes int) Clock {
|
||||
for minutes < 0 {
|
||||
// Keep adding 24 hours to the minutes value until it's positive
|
||||
minutes = minutes + (24 * 60)
|
||||
}
|
||||
minutes = minutes % (24 * 60)
|
||||
return Clock(minutes)
|
||||
}
|
69
go/clock/clock_test.go
Normal file
69
go/clock/clock_test.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package clock
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Clock type API:
|
||||
//
|
||||
// Time(hour, minute int) Clock // a "constructor"
|
||||
// (Clock) String() string // a "stringer"
|
||||
// (Clock) Add(minutes int) Clock
|
||||
//
|
||||
// Add should also handle subtraction by accepting negative values.
|
||||
// To satisfy the readme requirement about clocks being equal, values of
|
||||
// your Clock type need to work with the == operator.
|
||||
//
|
||||
// It might help to study the time.Time type in the standard library
|
||||
// (https://golang.org/pkg/time/#Time) as a model. See how constructors there
|
||||
// (Date and Now) return Time values rather than pointers. Note also how
|
||||
// most time.Time methods have value receivers rather that pointer recievers.
|
||||
// For more background on this read
|
||||
// https://github.com/golang/go/wiki/CodeReviewComments#receiver-type.
|
||||
|
||||
const testVersion = 2
|
||||
|
||||
// Retired testVersions
|
||||
// (none) 79937f6d58e25ebafe12d1cb4a9f88f4de70cfd6
|
||||
// 1 8d0cb8b617be2e36b2ca5ad2034e5f80f2372924
|
||||
|
||||
func TestCreateClock(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion)
|
||||
}
|
||||
for _, n := range timeTests {
|
||||
if got := Time(n.h, n.m); got.String() != n.want {
|
||||
t.Fatalf("Time(%d, %d) = %q, want %q", n.h, n.m, got, n.want)
|
||||
}
|
||||
}
|
||||
t.Log(len(timeTests), "test cases")
|
||||
}
|
||||
|
||||
func TestAddMinutes(t *testing.T) {
|
||||
for _, a := range addTests {
|
||||
if got := Time(a.h, a.m).Add(a.a); got.String() != a.want {
|
||||
t.Fatalf("Time(%d, %d).Add(%d) = %q, want %q",
|
||||
a.h, a.m, a.a, got, a.want)
|
||||
}
|
||||
}
|
||||
t.Log(len(addTests), "test cases")
|
||||
}
|
||||
|
||||
func TestCompareClocks(t *testing.T) {
|
||||
for _, e := range eqTests {
|
||||
clock1 := Time(e.c1.h, e.c1.m)
|
||||
clock2 := Time(e.c2.h, e.c2.m)
|
||||
got := clock1 == clock2
|
||||
if got != e.want {
|
||||
t.Log("Clock1:", clock1)
|
||||
t.Log("Clock2:", clock2)
|
||||
t.Logf("Clock1 == Clock2 is %t, want %t", got, e.want)
|
||||
if reflect.DeepEqual(clock1, clock2) {
|
||||
t.Log("(Hint: see comments in clock_test.go.)")
|
||||
}
|
||||
t.FailNow()
|
||||
}
|
||||
}
|
||||
t.Log(len(eqTests), "test cases")
|
||||
}
|
87
go/crypto-square/README.md
Normal file
87
go/crypto-square/README.md
Normal file
@@ -0,0 +1,87 @@
|
||||
# Crypto Square
|
||||
|
||||
Implement the classic method for composing secret messages called a square code.
|
||||
|
||||
The input is first normalized: The spaces and punctuation are removed
|
||||
from the English text and the message is downcased.
|
||||
|
||||
Then, the normalized characters are broken into rows. These rows can be
|
||||
regarded as forming a rectangle when printed with intervening newlines.
|
||||
|
||||
For example, the sentence
|
||||
|
||||
> If man was meant to stay on the ground god would have given us roots
|
||||
|
||||
is 54 characters long.
|
||||
|
||||
Broken into 8-character columns, it yields 7 rows.
|
||||
|
||||
Those 7 rows produce this rectangle when printed one per line:
|
||||
|
||||
```plain
|
||||
ifmanwas
|
||||
meanttos
|
||||
tayonthe
|
||||
groundgo
|
||||
dwouldha
|
||||
vegivenu
|
||||
sroots
|
||||
```
|
||||
|
||||
The coded message is obtained by reading down the columns going left to
|
||||
right.
|
||||
|
||||
For example, the message above is coded as:
|
||||
|
||||
```plain
|
||||
imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau
|
||||
```
|
||||
|
||||
Write a program that, given an English text, outputs the encoded version
|
||||
of that text.
|
||||
|
||||
The size of the square (number of columns) should be decided by the
|
||||
length of the message.
|
||||
|
||||
If the message is a length that creates a perfect square (e.g. 4, 9, 16,
|
||||
25, 36, etc), use that number of columns.
|
||||
|
||||
If the message doesn't fit neatly into a square, choose the number of
|
||||
columns that corresponds to the smallest square that is larger than the
|
||||
number of characters in the message.
|
||||
|
||||
For example, a message 4 characters long should use a 2 x 2 square. A
|
||||
message that is 81 characters long would use a square that is 9 columns
|
||||
wide.
|
||||
|
||||
A message between 5 and 8 characters long should use a rectangle 3
|
||||
characters wide.
|
||||
|
||||
Output the encoded text grouped by column.
|
||||
|
||||
For example:
|
||||
|
||||
- "Have a nice day. Feed the dog & chill out!"
|
||||
- Normalizes to: "haveanicedayfeedthedogchillout"
|
||||
- Which has length: 30
|
||||
- And splits into 5 6-character rows:
|
||||
- "havean"
|
||||
- "iceday"
|
||||
- "feedth"
|
||||
- "edogch"
|
||||
- "illout"
|
||||
- Which yields a ciphertext beginning: "hifei acedl v…"
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
J Dalbey's Programming Practice problems [view source](http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html)
|
45
go/crypto-square/crypto_square.go
Normal file
45
go/crypto-square/crypto_square.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package cryptosquare
|
||||
|
||||
import (
|
||||
"math"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TestVersion is an exercism thing
|
||||
const TestVersion = 1
|
||||
|
||||
// Encode implements the classic method for composing
|
||||
// secret messages called a square code
|
||||
func Encode(txt string) string {
|
||||
r := regexp.MustCompile("[^a-zA-Z0-9]+")
|
||||
nrm := strings.ToLower(r.ReplaceAllString(txt, ""))
|
||||
// The string should be normalized now (alphanumeric, lower case)
|
||||
sqrt := int(math.Ceil(math.Sqrt(float64(len(nrm)))))
|
||||
var square, ret []string
|
||||
var tmp string
|
||||
|
||||
// Build the initial square
|
||||
for i := 0; i < len(nrm); i++ {
|
||||
if i%sqrt == 0 && len(tmp) != 0 {
|
||||
square = append(square, tmp)
|
||||
tmp = ""
|
||||
}
|
||||
tmp += string(nrm[i])
|
||||
}
|
||||
square = append(square, tmp)
|
||||
tmp = ""
|
||||
|
||||
// Now rebuild the string by columns
|
||||
for i := 0; i < len(square[0]); i++ {
|
||||
for j := 0; j < len(square); j++ {
|
||||
if i < len(square[j]) {
|
||||
tmp += string(square[j][i])
|
||||
}
|
||||
}
|
||||
ret = append(ret, tmp)
|
||||
tmp = ""
|
||||
}
|
||||
|
||||
return strings.Join(ret, " ")
|
||||
}
|
111
go/crypto-square/crypto_square_test.go
Normal file
111
go/crypto-square/crypto_square_test.go
Normal file
@@ -0,0 +1,111 @@
|
||||
package cryptosquare
|
||||
|
||||
import "testing"
|
||||
|
||||
const testVersion = 1
|
||||
|
||||
// Retired testVersions
|
||||
// (none) 71ad8ac57fe7d5b777cfa1afd116cd41e1af55ed
|
||||
|
||||
var tests = []struct {
|
||||
pt string // plain text
|
||||
ct string // cipher text
|
||||
}{
|
||||
{
|
||||
"s#$%^&plunk",
|
||||
"su pn lk",
|
||||
},
|
||||
{
|
||||
"1, 2, 3 GO!",
|
||||
"1g 2o 3",
|
||||
},
|
||||
{
|
||||
"1234",
|
||||
"13 24",
|
||||
},
|
||||
{
|
||||
"123456789",
|
||||
"147 258 369",
|
||||
},
|
||||
{
|
||||
"123456789abc",
|
||||
"159 26a 37b 48c",
|
||||
},
|
||||
{
|
||||
"Never vex thine heart with idle woes",
|
||||
"neewl exhie vtetw ehaho ririe vntds",
|
||||
},
|
||||
{
|
||||
"ZOMG! ZOMBIES!!!",
|
||||
"zzi ooe mms gb",
|
||||
},
|
||||
{
|
||||
"Time is an illusion. Lunchtime doubly so.",
|
||||
"tasney inicds miohoo elntu illib suuml",
|
||||
},
|
||||
{
|
||||
"We all know interspecies romance is weird.",
|
||||
"wneiaw eorene awssci liprer lneoid ktcms",
|
||||
},
|
||||
{
|
||||
"Madness, and then illumination.",
|
||||
"msemo aanin dnin ndla etlt shui",
|
||||
},
|
||||
{
|
||||
"Vampires are people too!",
|
||||
"vrel aepe mset paoo irpo",
|
||||
},
|
||||
{
|
||||
"",
|
||||
"",
|
||||
},
|
||||
{
|
||||
"1",
|
||||
"1",
|
||||
},
|
||||
{
|
||||
"12",
|
||||
"1 2",
|
||||
},
|
||||
{
|
||||
"12 3",
|
||||
"13 2",
|
||||
},
|
||||
{
|
||||
"12345678",
|
||||
"147 258 36",
|
||||
},
|
||||
{
|
||||
"123456789a",
|
||||
"159 26a 37 48",
|
||||
},
|
||||
{
|
||||
"If man was meant to stay on the ground god would have given us roots",
|
||||
"imtgdvs fearwer mayoogo anouuio ntnnlvt wttddes aohghn sseoau",
|
||||
},
|
||||
{
|
||||
"Have a nice day. Feed the dog & chill out!",
|
||||
"hifei acedl veeol eddgo aatcu nyhht",
|
||||
},
|
||||
}
|
||||
|
||||
func TestEncode(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Errorf("Found TestVersion = %v, want %v.", TestVersion, testVersion)
|
||||
}
|
||||
for _, test := range tests {
|
||||
if ct := Encode(test.pt); ct != test.ct {
|
||||
t.Fatalf(`Encode(%q):
|
||||
got %q
|
||||
want %q`, test.pt, ct, test.ct)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEncode(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range tests {
|
||||
Encode(test.pt)
|
||||
}
|
||||
}
|
||||
}
|
1
go/current
Symbolic link
1
go/current
Symbolic link
@@ -0,0 +1 @@
|
||||
react
|
30
go/difference-of-squares/README.md
Normal file
30
go/difference-of-squares/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Difference Of Squares
|
||||
|
||||
Find the difference between the sum of the squares and the square of the sums of the first N natural numbers.
|
||||
|
||||
The square of the sum of the first ten natural numbers is,
|
||||
|
||||
(1 + 2 + ... + 10)**2 = 55**2 = 3025
|
||||
|
||||
The sum of the squares of the first ten natural numbers is,
|
||||
|
||||
1**2 + 2**2 + ... + 10**2 = 385
|
||||
|
||||
Hence the difference between the square of the sum of the first
|
||||
ten natural numbers and the sum of the squares is 2640:
|
||||
|
||||
3025 - 385 = 2640
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
Problem 6 at Project Euler [view source](http://projecteuler.net/problem=6)
|
32
go/difference-of-squares/difference_of_squares.go
Normal file
32
go/difference-of-squares/difference_of_squares.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package diffsquares
|
||||
|
||||
import "math"
|
||||
|
||||
// SquareOfSums calculates the Square of the sums
|
||||
// of the first 'num' natural numbers
|
||||
func SquareOfSums(num int) int {
|
||||
ret := 0
|
||||
for num > 0 {
|
||||
ret += num
|
||||
num--
|
||||
}
|
||||
return int(math.Pow(float64(ret), 2))
|
||||
}
|
||||
|
||||
// SumOfSquares calculates the Sum of the Squares
|
||||
// of the first 'num' natural numbers
|
||||
func SumOfSquares(num int) int {
|
||||
ret := 0
|
||||
for num > 0 {
|
||||
ret += int(math.Pow(float64(num), 2))
|
||||
num--
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Difference calculates the difference between
|
||||
// The SquareOfSums and the SumOfSquares for the
|
||||
// first 'num' natural numbers
|
||||
func Difference(num int) int {
|
||||
return SquareOfSums(num) - SumOfSquares(num)
|
||||
}
|
54
go/difference-of-squares/difference_of_squares_test.go
Normal file
54
go/difference-of-squares/difference_of_squares_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package diffsquares
|
||||
|
||||
import "testing"
|
||||
|
||||
var tests = []struct{ n, sqOfSums, sumOfSq int }{
|
||||
{5, 225, 55},
|
||||
{10, 3025, 385},
|
||||
{100, 25502500, 338350},
|
||||
}
|
||||
|
||||
func TestSquareOfSums(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
if s := SquareOfSums(test.n); s != test.sqOfSums {
|
||||
t.Fatalf("SquareOfSums(%d) = %d, want %d", test.n, s, test.sqOfSums)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSumOfSquares(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
if s := SumOfSquares(test.n); s != test.sumOfSq {
|
||||
t.Fatalf("SumOfSquares(%d) = %d, want %d", test.n, s, test.sumOfSq)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestDifference(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
want := test.sqOfSums - test.sumOfSq
|
||||
if s := Difference(test.n); s != want {
|
||||
t.Fatalf("Difference(%d) = %d, want %d", test.n, s, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark functions on just a single number (100, from the original PE problem)
|
||||
// to avoid overhead of iterating over tests.
|
||||
func BenchmarkSquareOfSums(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
SquareOfSums(100)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSumOfSquares(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
SumOfSquares(100)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkDifference(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Difference(100)
|
||||
}
|
||||
}
|
62
go/etl/README.md
Normal file
62
go/etl/README.md
Normal file
@@ -0,0 +1,62 @@
|
||||
# Etl
|
||||
|
||||
We are going to do the `Transform` step of an Extract-Transform-Load.
|
||||
|
||||
### ETL
|
||||
Extract-Transform-Load (ETL) is a fancy way of saying, "We have some crufty, legacy data over in this system, and now we need it in this shiny new system over here, so
|
||||
we're going to migrate this."
|
||||
|
||||
(Typically, this is followed by, "We're only going to need to run this
|
||||
once." That's then typically followed by much forehead slapping and
|
||||
moaning about how stupid we could possibly be.)
|
||||
|
||||
### The goal
|
||||
We're going to extract some scrabble scores from a legacy system.
|
||||
|
||||
The old system stored a list of letters per score:
|
||||
|
||||
- 1 point: "A", "E", "I", "O", "U", "L", "N", "R", "S", "T",
|
||||
- 2 points: "D", "G",
|
||||
- 3 points: "B", "C", "M", "P",
|
||||
- 4 points: "F", "H", "V", "W", "Y",
|
||||
- 5 points: "K",
|
||||
- 8 points: "J", "X",
|
||||
- 10 points: "Q", "Z",
|
||||
|
||||
The shiny new scrabble system instead stores the score per letter, which
|
||||
makes it much faster and easier to calculate the score for a word. It
|
||||
also stores the letters in lower-case regardless of the case of the
|
||||
input letters:
|
||||
|
||||
- "a" is worth 1 point.
|
||||
- "b" is worth 3 points.
|
||||
- "c" is worth 3 points.
|
||||
- "d" is worth 2 points.
|
||||
- Etc.
|
||||
|
||||
Your mission, should you choose to accept it, is to write a program that
|
||||
transforms the legacy data format to the shiny new format.
|
||||
|
||||
### Notes
|
||||
Note that both the old and the new system use strings to represent
|
||||
letters, even in languages that have a separate data type for
|
||||
characters.
|
||||
|
||||
A final note about scoring, Scrabble is played around the world in a
|
||||
variety of languages, each with its own unique scoring table. For
|
||||
example, an "A" is scored at 14 in the Basque-language version of the
|
||||
game while being scored at 9 in the Latin-language version.
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
The Jumpstart Lab team [view source](http://jumpstartlab.com)
|
17
go/etl/etl.go
Normal file
17
go/etl/etl.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package etl
|
||||
|
||||
import "strings"
|
||||
|
||||
// Transform takes the legacy data structure
|
||||
// and converts it into the new and improved
|
||||
// data structure oh man this new system will
|
||||
// make us so rich you guys.
|
||||
func Transform(input map[int][]string) map[string]int {
|
||||
ret := make(map[string]int)
|
||||
for k, v := range input {
|
||||
for _, let := range v {
|
||||
ret[strings.ToLower(let)] = k
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
90
go/etl/etl_test.go
Normal file
90
go/etl/etl_test.go
Normal file
@@ -0,0 +1,90 @@
|
||||
package etl
|
||||
|
||||
import "testing"
|
||||
|
||||
type given map[int][]string
|
||||
type expectation map[string]int
|
||||
|
||||
var transformTests = []struct {
|
||||
input given
|
||||
output expectation
|
||||
}{
|
||||
{
|
||||
given{1: {"A"}},
|
||||
expectation{"a": 1},
|
||||
},
|
||||
{
|
||||
given{1: {"A", "E", "I", "O", "U"}},
|
||||
expectation{"a": 1, "e": 1, "i": 1, "o": 1, "u": 1},
|
||||
},
|
||||
{
|
||||
given{
|
||||
1: {"A", "E"},
|
||||
2: {"D", "G"},
|
||||
},
|
||||
expectation{
|
||||
"a": 1,
|
||||
"e": 1,
|
||||
"d": 2,
|
||||
"g": 2,
|
||||
},
|
||||
},
|
||||
{
|
||||
given{
|
||||
1: {"A", "E", "I", "O", "U", "L", "N", "R", "S", "T"},
|
||||
2: {"D", "G"},
|
||||
3: {"B", "C", "M", "P"},
|
||||
4: {"F", "H", "V", "W", "Y"},
|
||||
5: {"K"},
|
||||
8: {"J", "X"},
|
||||
10: {"Q", "Z"},
|
||||
},
|
||||
expectation{
|
||||
"a": 1, "e": 1, "i": 1, "o": 1, "u": 1, "l": 1, "n": 1, "r": 1, "s": 1, "t": 1,
|
||||
"d": 2, "g": 2,
|
||||
"b": 3, "c": 3, "m": 3, "p": 3,
|
||||
"f": 4, "h": 4, "v": 4, "w": 4, "y": 4,
|
||||
"k": 5,
|
||||
"j": 8, "x": 8,
|
||||
"q": 10, "z": 10,
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
func equal(actual map[string]int, expectation map[string]int) bool {
|
||||
if len(actual) != len(expectation) {
|
||||
return false
|
||||
}
|
||||
|
||||
for k, actualVal := range actual {
|
||||
expectationVal, present := expectation[k]
|
||||
|
||||
if !present || actualVal != expectationVal {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
func TestTranform(t *testing.T) {
|
||||
for _, tt := range transformTests {
|
||||
actual := Transform(map[int][]string(tt.input))
|
||||
if !equal(actual, tt.output) {
|
||||
t.Fatalf("Transform(%v). Expected [%v], Actual [%v]", tt.input, tt.output, actual)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkTranform(b *testing.B) {
|
||||
b.StopTimer()
|
||||
for _, tt := range transformTests {
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
Transform(map[int][]string(tt.input))
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
}
|
||||
}
|
80
go/food-chain/README.md
Normal file
80
go/food-chain/README.md
Normal file
@@ -0,0 +1,80 @@
|
||||
# Food Chain
|
||||
|
||||
Write a program that generates the lyrics of the song 'I Know an Old Lady Who Swallowed a Fly'
|
||||
|
||||
Write a program that generates the lyrics to the song
|
||||
"I know an old lady who swallowed a fly". While you could
|
||||
copy/paste the lyrics, or read them from a file, this
|
||||
problem is much more interesting if you approach it
|
||||
algorithmically.
|
||||
|
||||
This is a [cumulative song](http://en.wikipedia.org/wiki/Cumulative_song) of unknown origin.
|
||||
|
||||
This is one of many common variants.
|
||||
|
||||
```plain
|
||||
I know an old lady who swallowed a fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.
|
||||
|
||||
I know an old lady who swallowed a spider.
|
||||
It wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.
|
||||
|
||||
I know an old lady who swallowed a bird.
|
||||
How absurd to swallow a bird!
|
||||
She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.
|
||||
|
||||
I know an old lady who swallowed a cat.
|
||||
Imagine that, to swallow a cat!
|
||||
She swallowed the cat to catch the bird.
|
||||
She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.
|
||||
|
||||
I know an old lady who swallowed a dog.
|
||||
What a hog, to swallow a dog!
|
||||
She swallowed the dog to catch the cat.
|
||||
She swallowed the cat to catch the bird.
|
||||
She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.
|
||||
|
||||
I know an old lady who swallowed a goat.
|
||||
Just opened her throat and swallowed a goat!
|
||||
She swallowed the goat to catch the dog.
|
||||
She swallowed the dog to catch the cat.
|
||||
She swallowed the cat to catch the bird.
|
||||
She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.
|
||||
|
||||
I know an old lady who swallowed a cow.
|
||||
I don't know how she swallowed a cow!
|
||||
She swallowed the cow to catch the goat.
|
||||
She swallowed the goat to catch the dog.
|
||||
She swallowed the dog to catch the cat.
|
||||
She swallowed the cat to catch the bird.
|
||||
She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.
|
||||
|
||||
I know an old lady who swallowed a horse.
|
||||
She's dead, of course!
|
||||
```
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
Wikipedia [view source](http://en.wikipedia.org/wiki/There_Was_an_Old_Lady_Who_Swallowed_a_Fly)
|
100
go/food-chain/food_chain.go
Normal file
100
go/food-chain/food_chain.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package foodchain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TestVersion is an exercism thing
|
||||
const TestVersion = 1
|
||||
|
||||
// An Inedible is something that you probably shouldn't eat.
|
||||
// At the least, you shouldn't eat it whole/live.
|
||||
type Inedible struct {
|
||||
// What it is
|
||||
Name string
|
||||
// A quick jab about it
|
||||
FollowUp string
|
||||
}
|
||||
|
||||
// DoNotEat is a non-exhaustive list of Inedibles. It's recommended
|
||||
// that you don't eat them. Yet the old lady did.
|
||||
var DoNotEat = []Inedible{
|
||||
Inedible{
|
||||
"fly", "I don't know why she swallowed the fly. Perhaps she'll die.",
|
||||
},
|
||||
Inedible{
|
||||
"spider", "It wriggled and jiggled and tickled inside her.",
|
||||
},
|
||||
Inedible{
|
||||
"bird", "How absurd to swallow a bird!",
|
||||
},
|
||||
Inedible{
|
||||
"cat", "Imagine that, to swallow a cat!",
|
||||
},
|
||||
Inedible{
|
||||
"dog", "What a hog, to swallow a dog!",
|
||||
},
|
||||
Inedible{
|
||||
"goat", "Just opened her throat and swallowed a goat!",
|
||||
},
|
||||
Inedible{
|
||||
"cow", "I don't know how she swallowed a cow!",
|
||||
},
|
||||
Inedible{
|
||||
"horse", "She's dead, of course!",
|
||||
},
|
||||
}
|
||||
|
||||
// Verse generates the text for a specific verse
|
||||
func Verse(verseNum int) string {
|
||||
return strings.Trim(Swallow(verseNum-1, true), "\n")
|
||||
}
|
||||
|
||||
// Verses generates the text for all verses from verse1 to verse2
|
||||
func Verses(verse1, verse2 int) string {
|
||||
var ret string
|
||||
for verse1 <= verse2 {
|
||||
ret += Verse(verse1) + "\n\n"
|
||||
verse1++
|
||||
}
|
||||
return strings.Trim(ret, "\n")
|
||||
}
|
||||
|
||||
// Song generates all verses
|
||||
func Song() string {
|
||||
var ret string
|
||||
for verseNum := 1; verseNum <= len(DoNotEat); verseNum++ {
|
||||
ret += Verse(verseNum) + "\n\n"
|
||||
}
|
||||
return strings.Trim(ret, "\n")
|
||||
}
|
||||
|
||||
// Swallow generates the text for swallowing something
|
||||
func Swallow(dneIdx int, first bool) string {
|
||||
var ret string
|
||||
|
||||
if first || dneIdx == len(DoNotEat)-1 {
|
||||
ret = fmt.Sprintf(
|
||||
"I know an old lady who swallowed a %s.\n%s\n",
|
||||
DoNotEat[dneIdx].Name,
|
||||
DoNotEat[dneIdx].FollowUp,
|
||||
)
|
||||
if dneIdx == 0 || dneIdx == len(DoNotEat)-1 {
|
||||
return ret
|
||||
}
|
||||
}
|
||||
ret += fmt.Sprintf("She swallowed the %s to catch the %s",
|
||||
DoNotEat[dneIdx].Name,
|
||||
DoNotEat[dneIdx-1].Name,
|
||||
)
|
||||
if DoNotEat[dneIdx-1].Name == "spider" {
|
||||
ret += " that wriggled and jiggled and tickled inside her.\n"
|
||||
} else if DoNotEat[dneIdx-1].Name == "fly" {
|
||||
ret += ".\nI don't know why she swallowed the fly. Perhaps she'll die.\n"
|
||||
return ret
|
||||
} else {
|
||||
ret += ".\n"
|
||||
}
|
||||
return ret + Swallow(dneIdx-1, false)
|
||||
}
|
95
go/food-chain/food_chain_test.go
Normal file
95
go/food-chain/food_chain_test.go
Normal file
@@ -0,0 +1,95 @@
|
||||
package foodchain
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const testVersion = 1
|
||||
|
||||
func TestTestVersion(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Errorf("Found TestVersion = %v, want %v.", TestVersion, testVersion)
|
||||
}
|
||||
}
|
||||
|
||||
var ref = []string{``,
|
||||
|
||||
`I know an old lady who swallowed a fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.`,
|
||||
|
||||
`I know an old lady who swallowed a spider.
|
||||
It wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.`,
|
||||
|
||||
`I know an old lady who swallowed a bird.
|
||||
How absurd to swallow a bird!
|
||||
She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.`,
|
||||
|
||||
`I know an old lady who swallowed a cat.
|
||||
Imagine that, to swallow a cat!
|
||||
She swallowed the cat to catch the bird.
|
||||
She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.`,
|
||||
|
||||
`I know an old lady who swallowed a dog.
|
||||
What a hog, to swallow a dog!
|
||||
She swallowed the dog to catch the cat.
|
||||
She swallowed the cat to catch the bird.
|
||||
She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.`,
|
||||
|
||||
`I know an old lady who swallowed a goat.
|
||||
Just opened her throat and swallowed a goat!
|
||||
She swallowed the goat to catch the dog.
|
||||
She swallowed the dog to catch the cat.
|
||||
She swallowed the cat to catch the bird.
|
||||
She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.`,
|
||||
|
||||
`I know an old lady who swallowed a cow.
|
||||
I don't know how she swallowed a cow!
|
||||
She swallowed the cow to catch the goat.
|
||||
She swallowed the goat to catch the dog.
|
||||
She swallowed the dog to catch the cat.
|
||||
She swallowed the cat to catch the bird.
|
||||
She swallowed the bird to catch the spider that wriggled and jiggled and tickled inside her.
|
||||
She swallowed the spider to catch the fly.
|
||||
I don't know why she swallowed the fly. Perhaps she'll die.`,
|
||||
|
||||
`I know an old lady who swallowed a horse.
|
||||
She's dead, of course!`,
|
||||
}
|
||||
|
||||
func TestVerse(t *testing.T) {
|
||||
for v := 1; v <= 8; v++ {
|
||||
if ret := Verse(v); ret != ref[v] {
|
||||
t.Fatalf("Verse(%d) =\n%s\n want:\n%s\n", v, ret, ref[v])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerses(t *testing.T) {
|
||||
if ret, want := Verses(1, 2), ref[1]+"\n\n"+ref[2]; ret != want {
|
||||
t.Fatalf("Verses(1, 2) =\n%s\n want:\n%s\n", ret, want)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestSong(t *testing.T) {
|
||||
if ret, want := Song(), strings.Join(ref[1:], "\n\n"); ret != want {
|
||||
t.Fatalf("Song() =\n%s\n want:\n%s\n", ret, want)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSong(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Song()
|
||||
}
|
||||
}
|
19
go/gigasecond/README.md
Normal file
19
go/gigasecond/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
# Gigasecond
|
||||
|
||||
Write a program that will calculate the date that someone turned or will celebrate their 1 Gs anniversary.
|
||||
|
||||
A gigasecond is one billion (10**9) seconds.
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
Chapter 9 in Chris Pine's online Learn to Program tutorial. [view source](http://pine.fm/LearnToProgram/?Chapter=09)
|
31
go/gigasecond/cases_test.go
Normal file
31
go/gigasecond/cases_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package gigasecond
|
||||
|
||||
// Source: exercism/x-common
|
||||
// Commit: 1e9e232 Merge pull request #45 from soniakeys/gigasecond-tests
|
||||
|
||||
// Add one gigasecond to the input.
|
||||
var addCases = []struct {
|
||||
in string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
"2011-04-25",
|
||||
"2043-01-01T01:46:40",
|
||||
},
|
||||
{
|
||||
"1977-06-13",
|
||||
"2009-02-19T01:46:40",
|
||||
},
|
||||
{
|
||||
"1959-07-19",
|
||||
"1991-03-27T01:46:40",
|
||||
},
|
||||
{
|
||||
"2015-01-24T22:00:00",
|
||||
"2046-10-02T23:46:40",
|
||||
},
|
||||
{
|
||||
"2015-01-24T23:59:59",
|
||||
"2046-10-03T01:46:39",
|
||||
},
|
||||
}
|
14
go/gigasecond/gigasecond.go
Normal file
14
go/gigasecond/gigasecond.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package gigasecond
|
||||
|
||||
import "time"
|
||||
|
||||
// TestVersion
|
||||
const TestVersion = 2 // find the value in gigasecond_test.go
|
||||
|
||||
// AddGigasecond Adds a gigasecond to the time t
|
||||
func AddGigasecond(t time.Time) time.Time {
|
||||
return t.Add(time.Second * 1000000000)
|
||||
}
|
||||
|
||||
// Birthday is my fake birthday
|
||||
var Birthday = time.Date(1979, 4, 23, 10, 2, 0, 0, time.UTC)
|
73
go/gigasecond/gigasecond_test.go
Normal file
73
go/gigasecond/gigasecond_test.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package gigasecond
|
||||
|
||||
// Write a function AddGigasecond that works with time.Time.
|
||||
// Also define a variable Birthday set to your (or someone else's) birthday.
|
||||
// Run go test -v to see your gigasecond anniversary.
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
const testVersion = 2
|
||||
|
||||
// Retired testVersions
|
||||
// (none) 98807b314216ff27492378a00df60410cc971d32
|
||||
// 1 ed0594b6fd6664928d17bbc70b543a56da05a5b8
|
||||
|
||||
// date formats used in test data
|
||||
const (
|
||||
fmtD = "2006-01-02"
|
||||
fmtDT = "2006-01-02T15:04:05"
|
||||
)
|
||||
|
||||
func TestAddGigasecond(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Fatalf("Found TestVersion = %v, want %v.", TestVersion, testVersion)
|
||||
}
|
||||
for _, tc := range addCases {
|
||||
in := parse(tc.in, t)
|
||||
want := parse(tc.want, t)
|
||||
got := AddGigasecond(in)
|
||||
if !got.Equal(want) {
|
||||
t.Fatalf(`AddGigasecond(%s)
|
||||
= %s
|
||||
want %s`, in, got, want)
|
||||
}
|
||||
}
|
||||
t.Log("Tested", len(addCases), "cases.")
|
||||
}
|
||||
|
||||
func TestYourAnniversary(t *testing.T) {
|
||||
t.Logf(`
|
||||
Your birthday: %s
|
||||
Your gigasecond anniversary: %s`, Birthday, AddGigasecond(Birthday))
|
||||
}
|
||||
|
||||
func parse(s string, t *testing.T) time.Time {
|
||||
tt, err := time.Parse(fmtDT, s) // try full date time format first
|
||||
if err != nil {
|
||||
tt, err = time.Parse(fmtD, s) // also allow just date
|
||||
}
|
||||
if err != nil {
|
||||
// can't run tests if input won't parse. if this seems to be a
|
||||
// development or ci environment, raise an error. if this condition
|
||||
// makes it to the solver though, ask for a bug report.
|
||||
_, statErr := os.Stat("example_gen.go")
|
||||
if statErr == nil || os.Getenv("TRAVIS_GO_VERSION") > "" {
|
||||
t.Fatal(err)
|
||||
} else {
|
||||
t.Log(err)
|
||||
t.Skip("(Not your problem. " +
|
||||
"please file issue at https://github.com/exercism/xgo.)")
|
||||
}
|
||||
}
|
||||
return tt
|
||||
}
|
||||
|
||||
func BenchmarkAddGigasecond(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
AddGigasecond(time.Time{})
|
||||
}
|
||||
}
|
41
go/grains/README.md
Normal file
41
go/grains/README.md
Normal file
@@ -0,0 +1,41 @@
|
||||
# Grains
|
||||
|
||||
Write a program that calculates the number of grains of wheat on a chessboard given that the number on each square doubles.
|
||||
|
||||
There once was a wise servant who saved the life of a prince. The king
|
||||
promised to pay whatever the servant could dream up. Knowing that the
|
||||
king loved chess, the servant told the king he would like to have grains
|
||||
of wheat. One grain on the first square of a chess board. Two grains on
|
||||
the next. Four on the third, and so on.
|
||||
|
||||
There are 64 squares on a chessboard.
|
||||
|
||||
Write a program that shows:
|
||||
- how many grains were on each square, and
|
||||
- the total number of grains
|
||||
|
||||
|
||||
## 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:
|
||||
|
||||
- Optimize for speed.
|
||||
- Optimize for readability.
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
JavaRanch Cattle Drive, exercise 6 [view source](http://www.javaranch.com/grains.jsp)
|
30
go/grains/grains.go
Normal file
30
go/grains/grains.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package grains
|
||||
|
||||
import "errors"
|
||||
|
||||
// Square just takes 1 * 2^sq
|
||||
func Square(sq int) (uint64, error) {
|
||||
if sq > 0 && sq < 65 {
|
||||
return (1 << uint(sq-1)), nil
|
||||
}
|
||||
return 0, errors.New("Invalid Square Requested")
|
||||
}
|
||||
|
||||
// TotalForSquare calculates the total number
|
||||
// for all squares up to sq (cause why not)
|
||||
func TotalForSquare(sq int) (uint64, error) {
|
||||
if sq < 0 || sq > 64 {
|
||||
return 0, errors.New("Invalid Square Requested")
|
||||
}
|
||||
var ret uint64
|
||||
for i := 0; i <= sq; i++ {
|
||||
ret = (ret << 1) | 1
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// Total calculates the total for the entire board
|
||||
func Total() uint64 {
|
||||
ret, _ := TotalForSquare(64)
|
||||
return ret
|
||||
}
|
61
go/grains/grains_test.go
Normal file
61
go/grains/grains_test.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package grains
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
var squareTests = []struct {
|
||||
input int
|
||||
expectedVal uint64
|
||||
expectError bool
|
||||
}{
|
||||
{1, 1, false},
|
||||
{2, 2, false},
|
||||
{3, 4, false},
|
||||
{4, 8, false},
|
||||
{16, 32768, false},
|
||||
{32, 2147483648, false},
|
||||
{64, 9223372036854775808, false},
|
||||
{65, 0, true},
|
||||
{0, 0, true},
|
||||
{-1, 0, true},
|
||||
}
|
||||
|
||||
func TestSquare(t *testing.T) {
|
||||
for _, test := range squareTests {
|
||||
actualVal, actualErr := Square(test.input)
|
||||
if actualVal != test.expectedVal {
|
||||
t.Errorf("Square(%d) expected %d, Actual %d", test.input, test.expectedVal, actualVal)
|
||||
}
|
||||
|
||||
// if we expect an error and there isn't one
|
||||
if test.expectError && actualErr == nil {
|
||||
t.Errorf("Square(%d) expected an error, but error is nil", test.input)
|
||||
}
|
||||
// if we don't expect an error and there is one
|
||||
if !test.expectError && actualErr != nil {
|
||||
t.Errorf("Square(%d) expected no error, but error is: %s", test.input, actualErr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestTotal(t *testing.T) {
|
||||
var expected uint64 = 18446744073709551615
|
||||
if actual := Total(); actual != expected {
|
||||
t.Errorf("Total() expected %d, Actual %d", expected, actual)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSquare(b *testing.B) {
|
||||
b.StopTimer()
|
||||
|
||||
for _, test := range squareTests {
|
||||
b.StartTimer()
|
||||
|
||||
for i := 0; i < b.N; i++ {
|
||||
Square(test.input)
|
||||
}
|
||||
|
||||
b.StopTimer()
|
||||
}
|
||||
}
|
50
go/hamming/README.md
Normal file
50
go/hamming/README.md
Normal file
@@ -0,0 +1,50 @@
|
||||
# Hamming
|
||||
|
||||
Write a program that can calculate the Hamming difference between two DNA strands.
|
||||
|
||||
A mutation is simply a mistake that occurs during the creation or
|
||||
copying of a nucleic acid, in particular DNA. Because nucleic acids are
|
||||
vital to cellular functions, mutations tend to cause a ripple effect
|
||||
throughout the cell. Although mutations are technically mistakes, a very
|
||||
rare mutation may equip the cell with a beneficial attribute. In fact,
|
||||
the macro effects of evolution are attributable by the accumulated
|
||||
result of beneficial microscopic mutations over many generations.
|
||||
|
||||
The simplest and most common type of nucleic acid mutation is a point
|
||||
mutation, which replaces one base with another at a single nucleotide.
|
||||
|
||||
By counting the number of differences between two homologous DNA strands
|
||||
taken from different genomes with a common ancestor, we get a measure of
|
||||
the minimum number of point mutations that could have occurred on the
|
||||
evolutionary path between the two strands.
|
||||
|
||||
This is called the 'Hamming distance'.
|
||||
|
||||
It is found by comparing two DNA strands and counting how many of the
|
||||
nucleotides are different from their equivalent in the other string.
|
||||
|
||||
GAGCCTACTAACGGGAT
|
||||
CATCGTAATGACGGCCT
|
||||
^ ^ ^ ^ ^ ^^
|
||||
|
||||
The Hamming distance between these two DNA strands is 7.
|
||||
|
||||
# Implementation notes
|
||||
|
||||
The Hamming distance is only defined for sequences of equal length. This means
|
||||
that based on the definition, each language could deal with getting sequences
|
||||
of equal length differently.
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
The Calculating Point Mutations problem at Rosalind [view source](http://rosalind.info/problems/hamm/)
|
81
go/hamming/cases_test.go
Normal file
81
go/hamming/cases_test.go
Normal file
@@ -0,0 +1,81 @@
|
||||
package hamming
|
||||
|
||||
// Source: exercism/x-common
|
||||
// Commit: c84e435 Merge pull request #51 from soniakeys/master
|
||||
|
||||
var testCases = []struct {
|
||||
s1 string
|
||||
s2 string
|
||||
want int
|
||||
}{
|
||||
{ // identical strands
|
||||
"A",
|
||||
"A",
|
||||
0,
|
||||
},
|
||||
{ // long identical strands
|
||||
"GGACTGA",
|
||||
"GGACTGA",
|
||||
0,
|
||||
},
|
||||
{ // complete distance in single nucleotide strands
|
||||
"A",
|
||||
"G",
|
||||
1,
|
||||
},
|
||||
{ // complete distance in small strands
|
||||
"AG",
|
||||
"CT",
|
||||
2,
|
||||
},
|
||||
{ // small distance in small strands
|
||||
"AT",
|
||||
"CT",
|
||||
1,
|
||||
},
|
||||
{ // small distance
|
||||
"GGACG",
|
||||
"GGTCG",
|
||||
1,
|
||||
},
|
||||
{ // small distance in long strands
|
||||
"ACCAGGG",
|
||||
"ACTATGG",
|
||||
2,
|
||||
},
|
||||
{ // non-unique character in first strand
|
||||
"AGA",
|
||||
"AGG",
|
||||
1,
|
||||
},
|
||||
{ // non-unique character in second strand
|
||||
"AGG",
|
||||
"AGA",
|
||||
1,
|
||||
},
|
||||
{ // large distance
|
||||
"GATACA",
|
||||
"GCATAA",
|
||||
4,
|
||||
},
|
||||
{ // large distance in off-by-one strand
|
||||
"GGACGGATTCTG",
|
||||
"AGGACGGATTCT",
|
||||
9,
|
||||
},
|
||||
{ // empty strands
|
||||
"",
|
||||
"",
|
||||
0,
|
||||
},
|
||||
{ // disallow first strand longer
|
||||
"AATG",
|
||||
"AAA",
|
||||
-1,
|
||||
},
|
||||
{ // disallow second strand longer
|
||||
"ATA",
|
||||
"AGTG",
|
||||
-1,
|
||||
},
|
||||
}
|
21
go/hamming/hamming.go
Normal file
21
go/hamming/hamming.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package hamming
|
||||
|
||||
import "errors"
|
||||
|
||||
// TestVersion is an exercism thing
|
||||
const TestVersion = 2
|
||||
|
||||
// Distance measures the hamming distance between two sequences
|
||||
// and returns the number if different bytes and an error value
|
||||
func Distance(seq1, seq2 string) (int, error) {
|
||||
if len(seq1) != len(seq2) {
|
||||
return -1, errors.New("Strands must be equal length")
|
||||
}
|
||||
var ret int
|
||||
for i := 0; i < len(seq1); i++ {
|
||||
if seq1[i] != seq2[i] {
|
||||
ret++
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
39
go/hamming/hamming_test.go
Normal file
39
go/hamming/hamming_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package hamming
|
||||
|
||||
import "testing"
|
||||
|
||||
const testVersion = 2
|
||||
|
||||
// Retired testVersions
|
||||
// (none) df178dc24b57f7d4ccf54d47430192749d56898f
|
||||
// 1 4f6fe21682f7f2a7845683cb26ff557208153ffe
|
||||
|
||||
func TestHamming(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Errorf("Found TestVersion = %v, want %v.", TestVersion, testVersion)
|
||||
}
|
||||
for _, tc := range testCases {
|
||||
switch got, err := Distance(tc.s1, tc.s2); {
|
||||
case err != nil:
|
||||
if tc.want >= 0 {
|
||||
t.Fatalf("Distance(%q, %q) returned error: %v",
|
||||
tc.s1, tc.s2, err)
|
||||
}
|
||||
case tc.want < 0:
|
||||
t.Fatalf("Distance(%q, %q) = %d. Expected error.",
|
||||
tc.s1, tc.s2, got)
|
||||
case got != tc.want:
|
||||
t.Fatalf("Distance(%q, %q) = %d, want %d.",
|
||||
tc.s1, tc.s2, got, tc.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkHamming(b *testing.B) {
|
||||
// bench combined time to run through all test cases
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, tc := range testCases {
|
||||
Distance(tc.s1, tc.s2)
|
||||
}
|
||||
}
|
||||
}
|
121
go/house/README.md
Normal file
121
go/house/README.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# House
|
||||
|
||||
Write a program that outputs the nursery rhyme 'This is the House that Jack Built'.
|
||||
|
||||
> [The] process of placing a phrase of clause within another phrase of
|
||||
> clause is called embedding. It is through the processes of recursion
|
||||
> and embedding that we are able to take a finite number of forms (words
|
||||
> and phrases) and construct an infinite number of expressions.
|
||||
> Furthermore, embedding also allows us to construct an infinitely long
|
||||
> structure, in theory anyway.
|
||||
|
||||
- [papyr.com](http://papyr.com/hypertextbooks/grammar/ph_noun.htm)
|
||||
|
||||
|
||||
The nursery rhyme reads as follows:
|
||||
|
||||
```plain
|
||||
This is the house that Jack built.
|
||||
|
||||
This is the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the man all tattered and torn
|
||||
that kissed the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the priest all shaven and shorn
|
||||
that married the man all tattered and torn
|
||||
that kissed the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the rooster that crowed in the morn
|
||||
that woke the priest all shaven and shorn
|
||||
that married the man all tattered and torn
|
||||
that kissed the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the farmer sowing his corn
|
||||
that kept the rooster that crowed in the morn
|
||||
that woke the priest all shaven and shorn
|
||||
that married the man all tattered and torn
|
||||
that kissed the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the horse and the hound and the horn
|
||||
that belonged to the farmer sowing his corn
|
||||
that kept the rooster that crowed in the morn
|
||||
that woke the priest all shaven and shorn
|
||||
that married the man all tattered and torn
|
||||
that kissed the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
```
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
British nursery rhyme [view source](http://en.wikipedia.org/wiki/This_Is_The_House_That_Jack_Built)
|
50
go/house/house.go
Normal file
50
go/house/house.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package house
|
||||
|
||||
// ASong holds the data we need to generate a song
|
||||
type ASong struct {
|
||||
start string
|
||||
clauses []string
|
||||
end string
|
||||
}
|
||||
|
||||
// Embed takes two strings and returns a string with the embedded
|
||||
func Embed(l, p string) string {
|
||||
return l + " " + p
|
||||
}
|
||||
|
||||
// Verse takes three things and returns a verse
|
||||
func Verse(start string, clause []string, end string) string {
|
||||
ret := start + " "
|
||||
for i := 0; i < len(clause); i++ {
|
||||
ret += clause[i] + " "
|
||||
}
|
||||
ret += end
|
||||
return ret
|
||||
}
|
||||
|
||||
// Song generates the whole song
|
||||
func Song() string {
|
||||
jackSong := ASong{
|
||||
start: "This is",
|
||||
clauses: []string{
|
||||
"the horse and the hound and the horn\nthat belonged to",
|
||||
"the farmer sowing his corn\nthat kept",
|
||||
"the rooster that crowed in the morn\nthat woke",
|
||||
"the priest all shaven and shorn\nthat married",
|
||||
"the man all tattered and torn\nthat kissed",
|
||||
"the maiden all forlorn\nthat milked",
|
||||
"the cow with the crumpled horn\nthat tossed",
|
||||
"the dog\nthat worried",
|
||||
"the cat\nthat killed",
|
||||
"the rat\nthat ate",
|
||||
"the malt\nthat lay in",
|
||||
},
|
||||
end: "the house that Jack built.",
|
||||
}
|
||||
var ret string
|
||||
for i := len(jackSong.clauses); i >= 0; i-- {
|
||||
ret += Verse(jackSong.start, jackSong.clauses[i:], jackSong.end) + "\n\n"
|
||||
}
|
||||
// Trim the trailing "\n\n"
|
||||
return ret[:len(ret)-2]
|
||||
}
|
171
go/house/house_test.go
Normal file
171
go/house/house_test.go
Normal file
@@ -0,0 +1,171 @@
|
||||
// Embed embeds a noun phrase as the object of relative clause with a
|
||||
// transitive verb.
|
||||
//
|
||||
// Argument relPhrase is a phrase with a relative clause, minus the object
|
||||
// of the clause. That is, relPhrase consists of a subject, a relative
|
||||
// pronoun, a transitive verb, possibly a preposition, but then no object.
|
||||
//
|
||||
// func Embed(relPhrase, nounPhrase string) string
|
||||
|
||||
// Verse generates a verse of a song with relative clauses that have
|
||||
// a recursive structure.
|
||||
//
|
||||
// func Verse(subject string, relPhrases []string, nounPhrase string) string
|
||||
//
|
||||
// There are different ways to do this of course, but try using Embed as a
|
||||
// subroutine and using programmatic recursion that reflects the grammatical
|
||||
// recursion.
|
||||
|
||||
// Song generates the full text of "The House That Jack Built". Oh yes, you
|
||||
// could just return a string literal, but humor us; use Verse as a subroutine.
|
||||
//
|
||||
// func Song() string
|
||||
|
||||
package house
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var (
|
||||
s = "This is"
|
||||
r = []string{
|
||||
"the cat that broke",
|
||||
"the vase that was on",
|
||||
}
|
||||
p = "the shelf."
|
||||
last = len(r) - 1
|
||||
// song copied from readme
|
||||
song = `This is the house that Jack built.
|
||||
|
||||
This is the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the man all tattered and torn
|
||||
that kissed the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the priest all shaven and shorn
|
||||
that married the man all tattered and torn
|
||||
that kissed the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the rooster that crowed in the morn
|
||||
that woke the priest all shaven and shorn
|
||||
that married the man all tattered and torn
|
||||
that kissed the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the farmer sowing his corn
|
||||
that kept the rooster that crowed in the morn
|
||||
that woke the priest all shaven and shorn
|
||||
that married the man all tattered and torn
|
||||
that kissed the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.
|
||||
|
||||
This is the horse and the hound and the horn
|
||||
that belonged to the farmer sowing his corn
|
||||
that kept the rooster that crowed in the morn
|
||||
that woke the priest all shaven and shorn
|
||||
that married the man all tattered and torn
|
||||
that kissed the maiden all forlorn
|
||||
that milked the cow with the crumpled horn
|
||||
that tossed the dog
|
||||
that worried the cat
|
||||
that killed the rat
|
||||
that ate the malt
|
||||
that lay in the house that Jack built.`
|
||||
)
|
||||
|
||||
func TestEmbed(t *testing.T) {
|
||||
l := r[last]
|
||||
want := l + " " + p
|
||||
if e := Embed(l, p); e != want {
|
||||
t.Fatalf("Embed(%q, %q) = %q, want %q.", l, p, e, want)
|
||||
}
|
||||
}
|
||||
|
||||
func TestVerse(t *testing.T) {
|
||||
for i := len(r); i >= 0; i-- {
|
||||
ri := r[i:]
|
||||
want := s + " " + strings.Join(append(ri, p), " ")
|
||||
if v := Verse(s, ri, p); v != want {
|
||||
t.Fatalf("Verse(%q, %q, %q) = %q, want %q.", s, ri, p, v, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestSong(t *testing.T) {
|
||||
s := Song()
|
||||
if s == song {
|
||||
return
|
||||
}
|
||||
fmt.Print(s)
|
||||
// a little help in locating an error
|
||||
got := strings.Split(s, "\n")
|
||||
want := strings.Split(song, "\n")
|
||||
var g, w string
|
||||
var i int
|
||||
for i, w = range want {
|
||||
if len(got) <= i {
|
||||
g = ""
|
||||
break
|
||||
}
|
||||
if g = got[i]; g != w {
|
||||
break
|
||||
}
|
||||
}
|
||||
t.Fatalf("Song() line %d = %q, want %q", i+1, g, w)
|
||||
}
|
24
go/largest-series-product/README.md
Normal file
24
go/largest-series-product/README.md
Normal file
@@ -0,0 +1,24 @@
|
||||
# Largest Series Product
|
||||
|
||||
Write a program that, when given a string of digits, can calculate the largest product for a series of consecutive digits of length n.
|
||||
|
||||
For example, for the input `'0123456789'`, the largest product for a
|
||||
series of 3 digits is 504 (7 * 8 * 9), and the largest product for a
|
||||
series of 5 digits is 15120 (5 * 6 * 7 * 8 * 9).
|
||||
|
||||
For the input `'73167176531330624919225119674426574742355349194934'`,
|
||||
the largest product for a series of 6 digits is 23520.
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
A variation on Problem 8 at Project Euler [view source](http://projecteuler.net/problem=8)
|
29
go/largest-series-product/cases_test.go
Normal file
29
go/largest-series-product/cases_test.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package lsproduct
|
||||
|
||||
// Source: exercism/x-common
|
||||
// Commit: 3764abd Merge pull request #167 from petertseng/largest-series-product-json
|
||||
|
||||
var tests = []struct {
|
||||
digits string
|
||||
span int
|
||||
product int64
|
||||
ok bool
|
||||
}{
|
||||
{"0123456789", 2, 72, true},
|
||||
{"576802143", 2, 48, true},
|
||||
{"29", 2, 18, true},
|
||||
{"0123456789", 3, 504, true},
|
||||
{"1027839564", 3, 270, true},
|
||||
{"0123456789", 5, 15120, true},
|
||||
{"73167176531330624919225119674426574742355349194934", 6, 23520, true},
|
||||
{"52677741234314237566414902593461595376319419139427", 6, 28350, true},
|
||||
{"7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450", 13, 23514624000, true},
|
||||
{"0000", 2, 0, true},
|
||||
{"99099", 3, 0, true},
|
||||
{"123", 4, -1, false},
|
||||
{"", 0, 1, true},
|
||||
{"123", 0, 1, true},
|
||||
{"", 1, -1, false},
|
||||
{"1234a5", 2, -1, false},
|
||||
{"12345", -1, -1, false},
|
||||
}
|
45
go/largest-series-product/largest_series_product.go
Normal file
45
go/largest-series-product/largest_series_product.go
Normal file
@@ -0,0 +1,45 @@
|
||||
package lsproduct
|
||||
|
||||
import "fmt"
|
||||
|
||||
// TestVersion defines version testing.
|
||||
const TestVersion = 1
|
||||
|
||||
// LargestSeriesProduct Takes an input string of digits
|
||||
// and a length for the series. It returns the largest
|
||||
// series product from that string of that length.
|
||||
func LargestSeriesProduct(input string, size int) (int, error) {
|
||||
if size == 0 {
|
||||
return 1, nil
|
||||
} else if size > len(input) {
|
||||
return 0, fmt.Errorf("Invalid Span Size")
|
||||
}
|
||||
var high int
|
||||
for i := 0; i < (len(input) - size + 1); i++ {
|
||||
try := GetProduct(input[i : i+size])
|
||||
if try < 0 {
|
||||
return 0, fmt.Errorf("Invalid input")
|
||||
}
|
||||
if try > high {
|
||||
high = try
|
||||
}
|
||||
}
|
||||
return high, nil
|
||||
}
|
||||
|
||||
// GetProduct takes a string of numbers, splits it up
|
||||
// and returns the product of them
|
||||
func GetProduct(input string) int {
|
||||
if len(input) > 0 {
|
||||
total := 1
|
||||
for i := range input {
|
||||
next := input[i] - 48
|
||||
if next < 0 || next > 9 {
|
||||
return -1
|
||||
}
|
||||
total = total * int(next)
|
||||
}
|
||||
return total
|
||||
}
|
||||
return 0
|
||||
}
|
92
go/largest-series-product/largest_series_product_test.go
Normal file
92
go/largest-series-product/largest_series_product_test.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package lsproduct
|
||||
|
||||
import "testing"
|
||||
|
||||
const testVersion = 1
|
||||
|
||||
// Retired testVersions
|
||||
// (none) ba7a22a355a32901caf46529c799fa53118ded0a
|
||||
|
||||
var tests = []struct {
|
||||
digits string
|
||||
span int
|
||||
product int64
|
||||
ok bool
|
||||
}{
|
||||
{"0123456789",
|
||||
2, 72, true},
|
||||
{"12",
|
||||
2, 2, true},
|
||||
{"19",
|
||||
2, 9, true},
|
||||
{"576802143",
|
||||
2, 48, true},
|
||||
{"0123456789",
|
||||
3, 504, true},
|
||||
{"1027839564",
|
||||
3, 270, true},
|
||||
{"0123456789",
|
||||
5, 15120, true},
|
||||
{"73167176531330624919225119674426574742355349194934",
|
||||
6, 23520, true},
|
||||
{"52677741234314237566414902593461595376319419139427",
|
||||
6, 28350, true},
|
||||
{"",
|
||||
0, 1, true},
|
||||
{"123",
|
||||
4, 0, false},
|
||||
{pe1k, 5, 40824, true}, // original PE problem
|
||||
{pe1k, 13, 23514624000, true}, // new PE problem
|
||||
}
|
||||
|
||||
const pe1k = "73167176531330624919225119674426574742355349194934" +
|
||||
"96983520312774506326239578318016984801869478851843" +
|
||||
"85861560789112949495459501737958331952853208805511" +
|
||||
"12540698747158523863050715693290963295227443043557" +
|
||||
"66896648950445244523161731856403098711121722383113" +
|
||||
"62229893423380308135336276614282806444486645238749" +
|
||||
"30358907296290491560440772390713810515859307960866" +
|
||||
"70172427121883998797908792274921901699720888093776" +
|
||||
"65727333001053367881220235421809751254540594752243" +
|
||||
"52584907711670556013604839586446706324415722155397" +
|
||||
"53697817977846174064955149290862569321978468622482" +
|
||||
"83972241375657056057490261407972968652414535100474" +
|
||||
"82166370484403199890008895243450658541227588666881" +
|
||||
"16427171479924442928230863465674813919123162824586" +
|
||||
"17866458359124566529476545682848912883142607690042" +
|
||||
"24219022671055626321111109370544217506941658960408" +
|
||||
"07198403850962455444362981230987879927244284909188" +
|
||||
"84580156166097919133875499200524063689912560717606" +
|
||||
"05886116467109405077541002256983155200055935729725" +
|
||||
"71636269561882670428252483600823257530420752963450"
|
||||
|
||||
func TestLargestSeriesProduct(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion)
|
||||
}
|
||||
for _, test := range tests {
|
||||
p, err := LargestSeriesProduct(test.digits, test.span)
|
||||
switch {
|
||||
case err != nil:
|
||||
if test.ok {
|
||||
t.Fatalf("LargestSeriesProduct(%s, %d) returned error %q. "+
|
||||
"Error not expected.",
|
||||
test.digits, test.span, err)
|
||||
}
|
||||
case !test.ok:
|
||||
t.Fatalf("LargestSeriesProduct(%s, %d) = %d, %v. Expected error",
|
||||
test.digits, test.span, p, err)
|
||||
case int64(p) != test.product:
|
||||
t.Fatalf("LargestSeriesProduct(%s, %d) = %d, want %d",
|
||||
test.digits, test.span, p, test.product)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLargestSeriesProduct(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range tests {
|
||||
LargestSeriesProduct(test.digits, test.span)
|
||||
}
|
||||
}
|
||||
}
|
38
go/leap/README.md
Normal file
38
go/leap/README.md
Normal file
@@ -0,0 +1,38 @@
|
||||
# Leap
|
||||
|
||||
Write a program that will take a year and report if it is a leap year.
|
||||
|
||||
The tricky thing here is that a leap year occurs:
|
||||
|
||||
```plain
|
||||
on every year that is evenly divisible by 4
|
||||
except every year that is evenly divisible by 100
|
||||
unless the year is also evenly divisible by 400
|
||||
```
|
||||
|
||||
For example, 1997 is not a leap year, but 1996 is. 1900 is not a leap
|
||||
year, but 2000 is.
|
||||
|
||||
If your language provides a method in the standard library that does
|
||||
this look-up, pretend it doesn't exist and implement it yourself.
|
||||
|
||||
## Notes
|
||||
|
||||
For a delightful, four minute explanation of the whole leap year
|
||||
phenomenon, go watch [this youtube video][video].
|
||||
|
||||
[video]: http://www.youtube.com/watch?v=xX96xng7sAE
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
JavaRanch Cattle Drive, exercise 3 [view source](http://www.javaranch.com/leap.jsp)
|
17
go/leap/cases_test.go
Normal file
17
go/leap/cases_test.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package leap
|
||||
|
||||
// Source: exercism/x-common
|
||||
// Commit: 945d08e Merge pull request #50 from soniakeys/master
|
||||
|
||||
var testCases = []struct {
|
||||
year int
|
||||
expected bool
|
||||
description string
|
||||
}{
|
||||
{1996, true, "leap year"},
|
||||
{1997, false, "non-leap year"},
|
||||
{1998, false, "non-leap even year"},
|
||||
{1900, false, "century"},
|
||||
{2400, true, "fourth century"},
|
||||
{2000, true, "Y2K"},
|
||||
}
|
15
go/leap/leap.go
Normal file
15
go/leap/leap.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package leap
|
||||
|
||||
// TestVersion is an exercism thing.
|
||||
const TestVersion = 1
|
||||
|
||||
// IsLeapYear returns whether the given year is a leap year.
|
||||
func IsLeapYear(year int) bool {
|
||||
if year%4 != 0 {
|
||||
return false
|
||||
}
|
||||
if year%400 == 0 {
|
||||
return true
|
||||
}
|
||||
return year%100 != 0
|
||||
}
|
34
go/leap/leap_test.go
Normal file
34
go/leap/leap_test.go
Normal file
@@ -0,0 +1,34 @@
|
||||
package leap
|
||||
|
||||
import "testing"
|
||||
|
||||
// Define a function IsLeapYear(int) bool.
|
||||
//
|
||||
// Also define an exported TestVersion with a value that matches
|
||||
// the internal testVersion here.
|
||||
|
||||
const testVersion = 1
|
||||
|
||||
// Retired testVersions
|
||||
// (none) 4a9e144a3c5dc0d9773f4cf641ffe3efe48641d8
|
||||
|
||||
func TestLeapYears(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion)
|
||||
}
|
||||
for _, test := range testCases {
|
||||
observed := IsLeapYear(test.year)
|
||||
if observed != test.expected {
|
||||
t.Fatalf("IsLeapYear(%d) = %t, want %t (%s)",
|
||||
test.year, observed, test.expected, test.description)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkLeapYears(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range testCases {
|
||||
IsLeapYear(test.year)
|
||||
}
|
||||
}
|
||||
}
|
71
go/luhn/README.md
Normal file
71
go/luhn/README.md
Normal file
@@ -0,0 +1,71 @@
|
||||
# Luhn
|
||||
|
||||
Write a program that can take a number and determine whether or not it is valid per the Luhn formula.
|
||||
|
||||
The Luhn formula is a simple checksum formula used to validate a variety
|
||||
of identification numbers, such as credit card numbers and Canadian
|
||||
Social Insurance Numbers.
|
||||
|
||||
The formula verifies a number against its included check digit, which is
|
||||
usually appended to a partial number to generate the full number. This
|
||||
number must pass the following test:
|
||||
|
||||
- Counting from rightmost digit (which is the check digit) and moving
|
||||
left, double the value of every second digit.
|
||||
- For any digits that thus become 10 or more, subtract 9 from the
|
||||
result.
|
||||
- 1111 becomes 2121.
|
||||
- 8763 becomes 7733 (from 2×6=12 → 12-9=3 and 2×8=16 → 16-9=7).
|
||||
- Add all these digits together.
|
||||
- 1111 becomes 2121 sums as 2+1+2+1 to give a check digit of 6.
|
||||
- 8763 becomes 7733, and 7+7+3+3 is 20.
|
||||
|
||||
If the total ends in 0 (put another way, if the total modulus 10 is
|
||||
congruent to 0), then the number is valid according to the Luhn formula;
|
||||
else it is not valid. So, 1111 is not valid (as shown above, it comes
|
||||
out to 6), while 8763 is valid (as shown above, it comes out to 20).
|
||||
|
||||
Write a program that, given a number
|
||||
|
||||
- Can check if it is valid per the Luhn formula. This should treat, for
|
||||
example, "2323 2005 7766 3554" as valid.
|
||||
- Can return the checksum, or the remainder from using the Luhn method.
|
||||
- Can add a check digit to make the number valid per the Luhn formula and
|
||||
return the original number plus that digit. This should give "2323 2005 7766
|
||||
3554" in response to "2323 2005 7766 355".
|
||||
|
||||
## About Checksums
|
||||
|
||||
A checksum has to do with error-detection. There are a number of different
|
||||
ways in which a checksum could be calculated.
|
||||
|
||||
When transmitting data, you might also send along a checksum that says how
|
||||
many bytes of data are being sent. That means that when the data arrives on
|
||||
the other side, you can count the bytes and compare it to the checksum. If
|
||||
these are different, then the data has been garbled in transmission.
|
||||
|
||||
In the Luhn problem the final digit acts as a sanity check for all the prior
|
||||
digits. Running those prior digits through a particular algorithm should give
|
||||
you that final digit.
|
||||
|
||||
It doesn't actually tell you if it's a real credit card number, only that it's
|
||||
a plausible one. It's the same thing with the bytes that get transmitted --
|
||||
you could have the right number of bytes and still have a garbled message. So
|
||||
checksums are a simple sanity-check, not a real in-depth verification of the
|
||||
authenticity of some data. It's often a cheap first pass, and can be used to
|
||||
quickly discard obviously invalid things.
|
||||
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
The Luhn Algorithm on Wikipedia [view source](http://en.wikipedia.org/wiki/Luhn_algorithm)
|
58
go/luhn/luhn.go
Normal file
58
go/luhn/luhn.go
Normal file
@@ -0,0 +1,58 @@
|
||||
package luhn
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"regexp"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Valid takes a numeric string and returns whether
|
||||
// it's Luhn valid.
|
||||
func Valid(toCheck string) bool {
|
||||
return GetRemainder(toCheck) == 0
|
||||
}
|
||||
|
||||
// GetRemainder returns the leftover from
|
||||
// running a number through the Luhn checker
|
||||
func GetRemainder(toCheck string) int {
|
||||
// Remove any non-numeric characters
|
||||
r := regexp.MustCompile("[^0-9]+")
|
||||
toCheck = r.ReplaceAllString(toCheck, "")
|
||||
|
||||
if len(toCheck) == 0 {
|
||||
return -1
|
||||
}
|
||||
var total int
|
||||
var double bool
|
||||
for i := range toCheck {
|
||||
var add int
|
||||
var err error
|
||||
idx := (len(toCheck) - 1) - i
|
||||
if add, err = strconv.Atoi(string(toCheck[idx])); err != nil {
|
||||
return -1
|
||||
}
|
||||
if double {
|
||||
add = add * 2
|
||||
if add >= 10 {
|
||||
add = add - 9
|
||||
}
|
||||
}
|
||||
double = !double
|
||||
total += add
|
||||
}
|
||||
return total % 10
|
||||
}
|
||||
|
||||
// AddCheck takes a number and returns the appropriate
|
||||
// number with an added digit that makes it valid
|
||||
func AddCheck(toCheck string) string {
|
||||
if GetRemainder(toCheck) != 0 {
|
||||
for i := 0; i <= 9; i++ {
|
||||
tst := fmt.Sprintf("%s%d", toCheck, i)
|
||||
if GetRemainder(tst) == 0 {
|
||||
return tst
|
||||
}
|
||||
}
|
||||
}
|
||||
return toCheck
|
||||
}
|
54
go/luhn/luhn_test.go
Normal file
54
go/luhn/luhn_test.go
Normal file
@@ -0,0 +1,54 @@
|
||||
package luhn
|
||||
|
||||
import "testing"
|
||||
|
||||
var validTests = []struct {
|
||||
n string
|
||||
ok bool
|
||||
}{
|
||||
{"738", false},
|
||||
{"8739567", true},
|
||||
{"1111", false},
|
||||
{"8763", true},
|
||||
{" ", false},
|
||||
{"", false},
|
||||
{"2323 2005 7766 3554", true},
|
||||
}
|
||||
|
||||
var addTests = []struct{ raw, luhn string }{
|
||||
{"123", "1230"},
|
||||
{"873956", "8739567"},
|
||||
{"837263756", "8372637564"},
|
||||
{"2323 2005 7766 355", "2323 2005 7766 3554"},
|
||||
// bonus Unicode cases
|
||||
// {"2323·2005·7766·355", "2323·2005·7766·3554"},
|
||||
// {"123", "1230"},
|
||||
}
|
||||
|
||||
func TestValid(t *testing.T) {
|
||||
for _, test := range validTests {
|
||||
if ok := Valid(test.n); ok != test.ok {
|
||||
t.Fatalf("Valid(%s) = %t, want %t.", test.n, ok, test.ok)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddCheck(t *testing.T) {
|
||||
for _, test := range addTests {
|
||||
if luhn := AddCheck(test.raw); luhn != test.luhn {
|
||||
t.Fatalf("AddCheck(%s) = %s, want %s.", test.raw, luhn, test.luhn)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkValid(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Valid("2323 2005 7766 3554")
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkAddCheck(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
AddCheck("2323 2005 7766 355")
|
||||
}
|
||||
}
|
20
go/palindrome-products/README.md
Normal file
20
go/palindrome-products/README.md
Normal file
@@ -0,0 +1,20 @@
|
||||
# Palindrome Products
|
||||
|
||||
Write a program that can detect palindrome products in a given range.
|
||||
|
||||
A palindromic number reads the same both ways. The largest palindrome
|
||||
made from the product of two 2-digit numbers is 9009 = 91 x 99.
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
Problem 4 at Project Euler [view source](http://projecteuler.net/problem=4)
|
91
go/palindrome-products/palindrome/palindrome_products.go
Normal file
91
go/palindrome-products/palindrome/palindrome_products.go
Normal file
@@ -0,0 +1,91 @@
|
||||
package palindrome
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Product is a palindromic product and all of its
|
||||
// factorizations
|
||||
type Product struct {
|
||||
Product int
|
||||
Factorizations [][2]int
|
||||
}
|
||||
|
||||
func createProduct(fac1, fac2 int) *Product {
|
||||
p := Product{Product: (fac1 * fac2)}
|
||||
p.addFactors(fac1, fac2)
|
||||
return &p
|
||||
}
|
||||
|
||||
func (p *Product) hasFactors(fac1, fac2 int) bool {
|
||||
for i := 0; i < len(p.Factorizations); i++ {
|
||||
if p.Factorizations[i][0] == fac1 && p.Factorizations[i][1] == fac2 {
|
||||
return true
|
||||
}
|
||||
if p.Factorizations[i][1] == fac1 && p.Factorizations[i][0] == fac2 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Product) addFactors(fac1, fac2 int) {
|
||||
if (fac1 * fac2) == p.Product {
|
||||
if !p.hasFactors(fac1, fac2) {
|
||||
p.Factorizations = append(p.Factorizations, [2]int{fac1, fac2})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Products takes a min and a max and finds
|
||||
func Products(fmin, fmax int) (Product, Product, error) {
|
||||
if fmin > fmax {
|
||||
return Product{}, Product{}, fmt.Errorf("fmin > fmax")
|
||||
}
|
||||
var pMin, pMax Product
|
||||
var err error
|
||||
var allProducts []Product
|
||||
|
||||
for i := fmin; i <= fmax; i++ {
|
||||
for j := fmin; j <= fmax; j++ {
|
||||
if isPalindrome(strconv.Itoa(i * j)) {
|
||||
var found bool
|
||||
for k := 0; k < len(allProducts); k++ {
|
||||
if allProducts[k].Product == (i * j) {
|
||||
allProducts[k].addFactors(i, j)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
allProducts = append(allProducts, *createProduct(i, j))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := range allProducts {
|
||||
if allProducts[i].Product > pMax.Product {
|
||||
// is the old pMax the new pMin?
|
||||
if len(pMin.Factorizations) == 0 {
|
||||
pMin = pMax
|
||||
}
|
||||
pMax = allProducts[i]
|
||||
} else {
|
||||
if allProducts[i].Product < pMin.Product {
|
||||
pMin = allProducts[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
fmt.Println(allProducts)
|
||||
return pMin, pMax, err
|
||||
}
|
||||
|
||||
func isPalindrome(s string) bool {
|
||||
for i := 0; i < (len(s) / 2); i++ {
|
||||
if s[i] != s[len(s)-1-i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
92
go/palindrome-products/palindrome_products.go
Normal file
92
go/palindrome-products/palindrome_products.go
Normal file
@@ -0,0 +1,92 @@
|
||||
package palindrome
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// Product is a palindromic product and all of its
|
||||
// factorizations
|
||||
type Product struct {
|
||||
Product int
|
||||
Factorizations [][2]int
|
||||
}
|
||||
|
||||
func createProduct(fac1, fac2 int) *Product {
|
||||
p := Product{Product: (fac1 * fac2)}
|
||||
p.addFactors(fac1, fac2)
|
||||
return &p
|
||||
}
|
||||
|
||||
func (p *Product) hasFactors(fac1, fac2 int) bool {
|
||||
for i := 0; i < len(p.Factorizations); i++ {
|
||||
if p.Factorizations[i][0] == fac1 && p.Factorizations[i][1] == fac2 {
|
||||
return true
|
||||
}
|
||||
if p.Factorizations[i][1] == fac1 && p.Factorizations[i][0] == fac2 {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *Product) addFactors(fac1, fac2 int) {
|
||||
if (fac1 * fac2) == p.Product {
|
||||
if !p.hasFactors(fac1, fac2) {
|
||||
p.Factorizations = append(p.Factorizations, [2]int{fac1, fac2})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Products takes a min and a max and finds
|
||||
func Products(fmin, fmax int) (Product, Product, error) {
|
||||
if fmin > fmax {
|
||||
return Product{}, Product{}, fmt.Errorf("fmin > fmax")
|
||||
}
|
||||
var pMin, pMax Product
|
||||
var allProducts []Product
|
||||
|
||||
for i := fmin; i <= fmax; i++ {
|
||||
for j := fmin; j <= fmax; j++ {
|
||||
if isPalindrome(strconv.Itoa(i * j)) {
|
||||
var found bool
|
||||
for k := 0; k < len(allProducts); k++ {
|
||||
if allProducts[k].Product == (i * j) {
|
||||
allProducts[k].addFactors(i, j)
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
allProducts = append(allProducts, *createProduct(i, j))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for i := range allProducts {
|
||||
if allProducts[i].Product > pMax.Product {
|
||||
// is the old pMax the new pMin?
|
||||
if len(pMin.Factorizations) == 0 {
|
||||
pMin = pMax
|
||||
}
|
||||
pMax = allProducts[i]
|
||||
} else {
|
||||
if allProducts[i].Product < pMin.Product {
|
||||
pMin = allProducts[i]
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(allProducts) == 0 {
|
||||
return pMin, pMax, fmt.Errorf("No palindromes")
|
||||
}
|
||||
return pMin, pMax, nil
|
||||
}
|
||||
|
||||
func isPalindrome(s string) bool {
|
||||
for i := 0; i < (len(s) / 2); i++ {
|
||||
if s[i] != s[len(s)-1-i] {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
98
go/palindrome-products/palindrome_products_test.go
Normal file
98
go/palindrome-products/palindrome_products_test.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package palindrome
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// API to impliment:
|
||||
// type Product struct {
|
||||
// Product int // palindromic, of course
|
||||
// // list of all possible two-factor factorizations of Product, within
|
||||
// // given limits, in order
|
||||
// Factorizations [][2]int
|
||||
// }
|
||||
// func Products(fmin, fmax int) (pmin, pmax Product, error)
|
||||
|
||||
var testData = []struct {
|
||||
// input to Products(): range limits for factors of the palindrome
|
||||
fmin, fmax int
|
||||
// output from Products():
|
||||
pmin, pmax Product // min and max palandromic products
|
||||
errPrefix string // start of text if there is an error, "" otherwise
|
||||
}{
|
||||
{1, 9,
|
||||
Product{}, // zero value means don't bother to test it
|
||||
Product{9, [][2]int{{1, 9}, {3, 3}}},
|
||||
""},
|
||||
{10, 99,
|
||||
Product{121, [][2]int{{11, 11}}},
|
||||
Product{9009, [][2]int{{91, 99}}},
|
||||
""},
|
||||
{100, 999,
|
||||
Product{10201, [][2]int{{101, 101}}},
|
||||
Product{906609, [][2]int{{913, 993}}},
|
||||
""},
|
||||
{4, 10, Product{}, Product{}, "No palindromes"},
|
||||
{10, 4, Product{}, Product{}, "fmin > fmax"},
|
||||
/* bonus curiosities. (can a negative number be a palindrome?
|
||||
// most say no
|
||||
{-99, -10, Product{}, Product{}, "Negative limits"},
|
||||
// but you can still get non-negative products from negative factors.
|
||||
{-99, -10,
|
||||
Product{121, [][2]int{{-11, -11}}},
|
||||
Product{9009, [][2]int{{-99, -91}}},
|
||||
""},
|
||||
{-2, 2,
|
||||
Product{0, [][2]int{{-2, 0}, {-1, 0}, {0, 0}, {0, 1}, {0, 2}}},
|
||||
Product{4, [][2]int{{-2, -2}, {2, 2}}},
|
||||
""},
|
||||
// or you could reverse the *digits*, keeping the minus sign in place.
|
||||
{-2, 2,
|
||||
Product{-4, [][2]int{{-2, 2}}},
|
||||
Product{4, [][2]int{{-2, -2}, {2, 2}}},
|
||||
""},
|
||||
{
|
||||
{0, (^uint(0))>>1, Product{}, Product{}, "This one's gonna overflow"},
|
||||
*/
|
||||
}
|
||||
|
||||
func TestPalindromeProducts(t *testing.T) {
|
||||
for _, test := range testData {
|
||||
// common preamble for test failures
|
||||
ret := fmt.Sprintf("Products(%d, %d) returned",
|
||||
test.fmin, test.fmax)
|
||||
// test
|
||||
pmin, pmax, err := Products(test.fmin, test.fmax)
|
||||
switch {
|
||||
case err == nil:
|
||||
if test.errPrefix > "" {
|
||||
t.Fatalf(ret+" err = nil, want %q", test.errPrefix+"...")
|
||||
}
|
||||
case test.errPrefix == "":
|
||||
t.Fatalf(ret+" err = %q, want nil", err)
|
||||
case !strings.HasPrefix(err.Error(), test.errPrefix):
|
||||
t.Fatalf(ret+" err = %q, want %q", err, test.errPrefix+"...")
|
||||
default:
|
||||
continue // correct error, no further tests for this test case
|
||||
}
|
||||
matchProd := func(ww string, rp, wp Product) {
|
||||
if len(wp.Factorizations) > 0 && // option to skip test
|
||||
!reflect.DeepEqual(rp, wp) {
|
||||
t.Fatal(ret, ww, "=", rp, "want", wp)
|
||||
}
|
||||
}
|
||||
matchProd("pmin", pmin, test.pmin)
|
||||
matchProd("pmax", pmax, test.pmax)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkPalindromeProducts(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range testData {
|
||||
Products(test.fmin, test.fmax)
|
||||
}
|
||||
}
|
||||
}
|
22
go/parallel-letter-frequency/README.md
Normal file
22
go/parallel-letter-frequency/README.md
Normal file
@@ -0,0 +1,22 @@
|
||||
# Parallel Letter Frequency
|
||||
|
||||
Write a program that counts the frequency of letters in texts using parallel computation.
|
||||
|
||||
Parallelism is about doing things in parallel that can also be done
|
||||
sequentially. A common example is counting the frequency of letters.
|
||||
Create a function that returns the total frequency of each letter in a
|
||||
list of texts and that employs parallelism.
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
[view source]()
|
27
go/parallel-letter-frequency/by_the_letter.go
Normal file
27
go/parallel-letter-frequency/by_the_letter.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package letter
|
||||
|
||||
import "time"
|
||||
|
||||
// ConcurrentFrequency concurrently calls Frequency
|
||||
// and returns the final Frequency Map
|
||||
func ConcurrentFrequency(input []string) FreqMap {
|
||||
var procCnt = len(input)
|
||||
var toMerge []FreqMap
|
||||
for _, chunk := range input {
|
||||
go func(chunk string) {
|
||||
toMerge = append(toMerge, Frequency(chunk))
|
||||
procCnt--
|
||||
}(chunk)
|
||||
}
|
||||
for procCnt > 0 {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
// We should have all FreqMaps now... merge them
|
||||
ret := make(map[rune]int)
|
||||
for _, aResult := range toMerge {
|
||||
for k, v := range aResult {
|
||||
ret[k] += v
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
11
go/parallel-letter-frequency/frequency.go
Normal file
11
go/parallel-letter-frequency/frequency.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package letter
|
||||
|
||||
type FreqMap map[rune]int
|
||||
|
||||
func Frequency(s string) FreqMap {
|
||||
m := FreqMap{}
|
||||
for _, r := range s {
|
||||
m[r]++
|
||||
}
|
||||
return m
|
||||
}
|
30
go/parallel-letter-frequency/letter.go
Normal file
30
go/parallel-letter-frequency/letter.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package letter
|
||||
|
||||
import (
|
||||
"sync"
|
||||
"time"
|
||||
)
|
||||
|
||||
// MyConcurrentFrequency ...
|
||||
func MyConcurrentFrequency(input []string) FreqMap {
|
||||
var ProcMap = struct {
|
||||
sync.RWMutex
|
||||
m map[rune]int
|
||||
}{m: make(map[rune]int)}
|
||||
|
||||
var procCnt = len(input)
|
||||
for _, chunk := range input {
|
||||
go func(chunk string) {
|
||||
for _, rn := range chunk {
|
||||
ProcMap.Lock()
|
||||
ProcMap.m[rn]++
|
||||
ProcMap.Unlock()
|
||||
}
|
||||
procCnt--
|
||||
}(chunk)
|
||||
}
|
||||
for procCnt > 0 {
|
||||
time.Sleep(time.Millisecond)
|
||||
}
|
||||
return ProcMap.m
|
||||
}
|
@@ -0,0 +1,72 @@
|
||||
package letter
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// In the separate file frequency.go, you are given a function, Frequency(),
|
||||
// to sequentially count letter frequencies in a single text.
|
||||
// Perform this exercise on parallelism using Go concurrency features.
|
||||
// Make concurrent calls to Frequency and combine results to obtain the answer.
|
||||
|
||||
func TestConcurrentFrequency(t *testing.T) {
|
||||
seq := Frequency(euro + dutch + us)
|
||||
con := ConcurrentFrequency([]string{euro, dutch, us})
|
||||
if !reflect.DeepEqual(con, seq) {
|
||||
t.Fatal("ConcurrentFrequency wrong result")
|
||||
}
|
||||
}
|
||||
|
||||
var (
|
||||
euro = `Freude schöner Götterfunken
|
||||
Tochter aus Elysium,
|
||||
Wir betreten feuertrunken,
|
||||
Himmlische, dein Heiligtum!
|
||||
Deine Zauber binden wieder
|
||||
Was die Mode streng geteilt;
|
||||
Alle Menschen werden Brüder,
|
||||
Wo dein sanfter Flügel weilt.`
|
||||
dutch = `Wilhelmus van Nassouwe
|
||||
ben ik, van Duitsen bloed,
|
||||
den vaderland getrouwe
|
||||
blijf ik tot in den dood.
|
||||
Een Prinse van Oranje
|
||||
ben ik, vrij, onverveerd,
|
||||
den Koning van Hispanje
|
||||
heb ik altijd geëerd.`
|
||||
us = `O say can you see by the dawn's early light,
|
||||
What so proudly we hailed at the twilight's last gleaming,
|
||||
Whose broad stripes and bright stars through the perilous fight,
|
||||
O'er the ramparts we watched, were so gallantly streaming?
|
||||
And the rockets' red glare, the bombs bursting in air,
|
||||
Gave proof through the night that our flag was still there;
|
||||
O say does that star-spangled banner yet wave,
|
||||
O'er the land of the free and the home of the brave?`
|
||||
)
|
||||
|
||||
func BenchmarkConcurrentFrequency(b *testing.B) {
|
||||
b.StopTimer()
|
||||
var bTest []string
|
||||
for i := 0; i < 5; i++ {
|
||||
bTest = append(bTest, euro)
|
||||
bTest = append(bTest, dutch)
|
||||
bTest = append(bTest, us)
|
||||
}
|
||||
b.StartTimer()
|
||||
ConcurrentFrequency(bTest)
|
||||
b.StopTimer()
|
||||
}
|
||||
|
||||
func BenchmarkMyConcurrentFrequency(b *testing.B) {
|
||||
b.StopTimer()
|
||||
var bTest []string
|
||||
for i := 0; i < 5; i++ {
|
||||
bTest = append(bTest, euro)
|
||||
bTest = append(bTest, dutch)
|
||||
bTest = append(bTest, us)
|
||||
}
|
||||
b.StartTimer()
|
||||
MyConcurrentFrequency(bTest)
|
||||
b.StopTimer()
|
||||
}
|
29
go/pascals-triangle/README.md
Normal file
29
go/pascals-triangle/README.md
Normal file
@@ -0,0 +1,29 @@
|
||||
# Pascals Triangle
|
||||
|
||||
Write a program that computes Pascal's triangle up to a given number of rows.
|
||||
|
||||
In Pascal's Triangle each number is computed by adding the numbers to
|
||||
the right and left of the current position in the previous row.
|
||||
|
||||
```plain
|
||||
1
|
||||
1 1
|
||||
1 2 1
|
||||
1 3 3 1
|
||||
1 4 6 4 1
|
||||
# ... etc
|
||||
```
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
Pascal's Triangle at Wolfram Math World [view source](http://mathworld.wolfram.com/PascalsTriangle.html)
|
26
go/pascals-triangle/pascal.go
Normal file
26
go/pascals-triangle/pascal.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package pascal
|
||||
|
||||
// Triangle returns pascals triangle up to depth
|
||||
func Triangle(depth int) [][]int {
|
||||
var ret [][]int
|
||||
for currDepth := 0; currDepth < depth; currDepth++ {
|
||||
var newRow, prevRow []int
|
||||
// Each row is currDepth+1 long
|
||||
rowLength := currDepth + 1
|
||||
// Rows start with a 1
|
||||
newRow = append(newRow, 1)
|
||||
if currDepth > 0 {
|
||||
prevRow = ret[currDepth-1]
|
||||
}
|
||||
for i := 1; i < rowLength; i++ {
|
||||
if i == rowLength-1 {
|
||||
// Rows end with a 1 also
|
||||
newRow = append(newRow, 1)
|
||||
break
|
||||
}
|
||||
newRow = append(newRow, prevRow[i-1]+prevRow[i])
|
||||
}
|
||||
ret = append(ret, newRow)
|
||||
}
|
||||
return ret
|
||||
}
|
BIN
go/pascals-triangle/pascal_printer
Executable file
BIN
go/pascals-triangle/pascal_printer
Executable file
Binary file not shown.
22
go/pascals-triangle/pascal_printer.go
Normal file
22
go/pascals-triangle/pascal_printer.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"gogs.bullercodeworks.com/brian/pascal"
|
||||
)
|
||||
|
||||
func main() {
|
||||
if len(os.Args) == 2 {
|
||||
if num, err := strconv.Atoi(os.Args[1]); err == nil {
|
||||
ret := pascal.Triangle(num)
|
||||
for i := range ret {
|
||||
fmt.Println(ret[i])
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
fmt.Println("Usage: ./pascal_printer <depth>")
|
||||
}
|
49
go/pascals-triangle/pascals_triangle_test.go
Normal file
49
go/pascals-triangle/pascals_triangle_test.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package pascal
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var t20 = [][]int{
|
||||
{1},
|
||||
{1, 1},
|
||||
{1, 2, 1},
|
||||
{1, 3, 3, 1},
|
||||
{1, 4, 6, 4, 1},
|
||||
{1, 5, 10, 10, 5, 1},
|
||||
{1, 6, 15, 20, 15, 6, 1},
|
||||
{1, 7, 21, 35, 35, 21, 7, 1},
|
||||
{1, 8, 28, 56, 70, 56, 28, 8, 1},
|
||||
{1, 9, 36, 84, 126, 126, 84, 36, 9, 1},
|
||||
{1, 10, 45, 120, 210, 252, 210, 120, 45, 10, 1},
|
||||
{1, 11, 55, 165, 330, 462, 462, 330, 165, 55, 11, 1},
|
||||
{1, 12, 66, 220, 495, 792, 924, 792, 495, 220, 66, 12, 1},
|
||||
{1, 13, 78, 286, 715, 1287, 1716, 1716, 1287, 715, 286, 78, 13, 1},
|
||||
{1, 14, 91, 364, 1001, 2002, 3003, 3432, 3003, 2002, 1001, 364, 91, 14, 1},
|
||||
{1, 15, 105, 455, 1365, 3003, 5005, 6435, 6435, 5005, 3003, 1365, 455, 105, 15, 1},
|
||||
{1, 16, 120, 560, 1820, 4368, 8008, 11440, 12870, 11440, 8008, 4368, 1820, 560, 120, 16, 1},
|
||||
{1, 17, 136, 680, 2380, 6188, 12376, 19448, 24310, 24310, 19448, 12376, 6188, 2380, 680, 136, 17, 1},
|
||||
{1, 18, 153, 816, 3060, 8568, 18564, 31824, 43758, 48620, 43758, 31824, 18564, 8568, 3060, 816, 153, 18, 1},
|
||||
{1, 19, 171, 969, 3876, 11628, 27132, 50388, 75582, 92378, 92378, 75582, 50388, 27132, 11628, 3876, 969, 171, 19, 1},
|
||||
}
|
||||
|
||||
func TestTriangle(t *testing.T) {
|
||||
for n := 1; n <= 20; n++ {
|
||||
res := Triangle(n)
|
||||
want := t20[:n]
|
||||
if !reflect.DeepEqual(res, want) {
|
||||
t.Fatalf("Triangle(%d) = %s,\nwant:%s\n",
|
||||
n, format(res), format(want))
|
||||
}
|
||||
}
|
||||
t.Log(format(Triangle(20)))
|
||||
}
|
||||
|
||||
func format(t [][]int) (s string) {
|
||||
for _, r := range t {
|
||||
s = fmt.Sprintf("%s\n%v", s, r)
|
||||
}
|
||||
return
|
||||
}
|
30
go/pythagorean-triplet/README.md
Normal file
30
go/pythagorean-triplet/README.md
Normal file
@@ -0,0 +1,30 @@
|
||||
# Pythagorean Triplet
|
||||
|
||||
There exists exactly one Pythagorean triplet for which a + b + c = 1000. Find the product a * b * c.
|
||||
|
||||
A Pythagorean triplet is a set of three natural numbers, {a, b, c}, for
|
||||
which,
|
||||
|
||||
```
|
||||
a**2 + b**2 = c**2
|
||||
```
|
||||
|
||||
For example,
|
||||
|
||||
```
|
||||
3**2 + 4**2 = 9 + 16 = 25 = 5**2.
|
||||
```
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
Problem 9 at Project Euler [view source](http://projecteuler.net/problem=9)
|
44
go/pythagorean-triplet/pythagorean.go
Normal file
44
go/pythagorean-triplet/pythagorean.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package pythagorean
|
||||
|
||||
import "math"
|
||||
|
||||
// Triplet just holds three ints
|
||||
type Triplet struct {
|
||||
a, b, c int
|
||||
}
|
||||
|
||||
// Range finds all pythagorean triplets
|
||||
// from min to max
|
||||
func Range(min, max int) []Triplet {
|
||||
var ret []Triplet
|
||||
for a := min; a <= max; a++ {
|
||||
for b := a + 1; b <= max; b++ {
|
||||
cSq := float64(a*a + b*b)
|
||||
c := int(math.Sqrt(cSq))
|
||||
if c >= min && c <= max && isTriplet(a, b, c) {
|
||||
ret = append(ret, Triplet{a, b, c})
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// Sum finds all triplets that sum up to total
|
||||
func Sum(total int) []Triplet {
|
||||
var ret []Triplet
|
||||
|
||||
// No side of a triangle can be over 1/2 of the total
|
||||
for a := 1; a <= (total / 2); a++ {
|
||||
for b := a; b <= (total / 2); b++ {
|
||||
c := total - a - b
|
||||
if isTriplet(a, b, c) {
|
||||
ret = append(ret, Triplet{a, b, c})
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func isTriplet(a, b, c int) bool {
|
||||
return (a*a + b*b) == c*c
|
||||
}
|
73
go/pythagorean-triplet/pythagorean_triplet_test.go
Normal file
73
go/pythagorean-triplet/pythagorean_triplet_test.go
Normal file
@@ -0,0 +1,73 @@
|
||||
package pythagorean
|
||||
|
||||
// Use this type definition,
|
||||
//
|
||||
// type Triplet [3]int
|
||||
//
|
||||
// and implement two functions,
|
||||
//
|
||||
// Range(min, max int) []Triplet
|
||||
// Sum(p int) []Triplet
|
||||
//
|
||||
// Range returns a list of all Pythagorean triplets with sides in the
|
||||
// range min to max inclusive.
|
||||
//
|
||||
// Sum returns a list of all Pythagorean triplets where the sum a+b+c
|
||||
// (the perimeter) is equal to p.
|
||||
//
|
||||
// The three elements of each returned triplet must be in order,
|
||||
// t[0] <= t[1] <= t[2], and the list of triplets must be in lexicographic
|
||||
// order.
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
var rangeTests = []struct {
|
||||
min, max int
|
||||
ts []Triplet
|
||||
}{
|
||||
{1, 10, []Triplet{{3, 4, 5}, {6, 8, 10}}},
|
||||
{11, 20, []Triplet{{12, 16, 20}}},
|
||||
}
|
||||
|
||||
func TestRange(t *testing.T) {
|
||||
for _, test := range rangeTests {
|
||||
ts := Range(test.min, test.max)
|
||||
if !reflect.DeepEqual(ts, test.ts) {
|
||||
t.Fatalf("Range(%d, %d) = %v, want %v",
|
||||
test.min, test.max, ts, test.ts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sumTests = []struct {
|
||||
sum int
|
||||
ts []Triplet
|
||||
}{
|
||||
{180, []Triplet{{18, 80, 82}, {30, 72, 78}, {45, 60, 75}}},
|
||||
{1000, []Triplet{{200, 375, 425}}},
|
||||
}
|
||||
|
||||
func TestSum(t *testing.T) {
|
||||
for _, test := range sumTests {
|
||||
ts := Sum(test.sum)
|
||||
if !reflect.DeepEqual(ts, test.ts) {
|
||||
t.Fatalf("Sum(%d) = %v, want %v",
|
||||
test.sum, ts, test.ts)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRange(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Range(1, 100)
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkSum(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
Sum(1000)
|
||||
}
|
||||
}
|
40
go/queen-attack/README.md
Normal file
40
go/queen-attack/README.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Queen Attack
|
||||
|
||||
Write a program that positions two queens on a chess board and indicates whether or not they are positioned so that they can attack each other.
|
||||
|
||||
In the game of chess, a queen can attack pieces which are on the same
|
||||
row, column, or diagonal.
|
||||
|
||||
A chessboard can be represented by an 8 by 8 array.
|
||||
|
||||
So if you're told the white queen is at (2, 3) and the black queen at
|
||||
(5, 6), then you'd know you've got a set-up like so:
|
||||
|
||||
```plain
|
||||
_ _ _ _ _ _ _ _
|
||||
_ _ _ _ _ _ _ _
|
||||
_ _ _ W _ _ _ _
|
||||
_ _ _ _ _ _ _ _
|
||||
_ _ _ _ _ _ _ _
|
||||
_ _ _ _ _ _ B _
|
||||
_ _ _ _ _ _ _ _
|
||||
_ _ _ _ _ _ _ _
|
||||
```
|
||||
|
||||
You'd also be able to answer whether the queens can attack each other.
|
||||
In this case, that answer would be yes, they can, because both pieces
|
||||
share a diagonal.
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
J Dalbey's Programming Practice problems [view source](http://users.csc.calpoly.edu/~jdalbey/103/Projects/ProgrammingPractice.html)
|
29
go/queen-attack/queen_attack.go
Normal file
29
go/queen-attack/queen_attack.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package queenattack
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"math"
|
||||
)
|
||||
|
||||
// CanQueenAttack takes two positions one for a
|
||||
// white queen (wq) and one for a black queen (bq)
|
||||
// it returns a boolean value: if an attack can
|
||||
// be made, and an error
|
||||
func CanQueenAttack(wq, bq string) (bool, error) {
|
||||
if len(wq) != 2 || len(bq) != 2 ||
|
||||
wq[0] < 'a' || wq[0] > 'z' ||
|
||||
wq[1] < '0' || wq[1] > '8' ||
|
||||
bq[0] < 'a' || bq[0] > 'z' ||
|
||||
bq[1] < '0' || bq[1] > '8' ||
|
||||
wq == bq {
|
||||
return false, errors.New("Invalid pieces/placement")
|
||||
}
|
||||
wx, wy := float64(int8(wq[0])), float64(int8(wq[1]))
|
||||
bx, by := float64(int8(bq[0])), float64(int8(bq[1]))
|
||||
if wx == bx || wy == by ||
|
||||
math.Abs(wx-bx) == math.Abs(wy-by) {
|
||||
return true, nil
|
||||
}
|
||||
|
||||
return false, nil
|
||||
}
|
53
go/queen-attack/queen_attack_test.go
Normal file
53
go/queen-attack/queen_attack_test.go
Normal file
@@ -0,0 +1,53 @@
|
||||
package queenattack
|
||||
|
||||
import "testing"
|
||||
|
||||
// Arguments to CanQueenAttack are in algebraic notation.
|
||||
// See http://en.wikipedia.org/wiki/Algebraic_notation_(chess)
|
||||
|
||||
var tests = []struct {
|
||||
w, b string
|
||||
attack bool
|
||||
ok bool
|
||||
}{
|
||||
{"b4", "b4", false, false}, // same square
|
||||
{"a8", "b9", false, false}, // off board
|
||||
{"here", "there", false, false}, // invalid
|
||||
{"", "", false, false},
|
||||
|
||||
{"b3", "d7", false, true}, // no attack
|
||||
{"b4", "b7", true, true}, // same file
|
||||
{"e4", "b4", true, true}, // same rank
|
||||
{"a1", "f6", true, true}, // common diagonals
|
||||
{"a6", "b7", true, true},
|
||||
{"d1", "f3", true, true},
|
||||
{"f1", "a6", true, true},
|
||||
}
|
||||
|
||||
func TestCanQueenAttack(t *testing.T) {
|
||||
for _, test := range tests {
|
||||
switch attack, err := CanQueenAttack(test.w, test.b); {
|
||||
case err != nil:
|
||||
if test.ok {
|
||||
t.Fatalf("CanQueenAttack(%s, %s) returned error %q. "+
|
||||
"Error not expected.",
|
||||
test.w, test.b, err)
|
||||
}
|
||||
case !test.ok:
|
||||
t.Fatalf("CanQueenAttack(%s, %s) = %t, %v. Expected error.",
|
||||
test.w, test.b, attack, err)
|
||||
case attack != test.attack:
|
||||
t.Fatalf("CanQueenAttack(%s, %s) = %t, want %t.",
|
||||
test.w, test.b, attack, test.attack)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark combined time for all test cases
|
||||
func BenchmarkCanQueenAttack(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range tests {
|
||||
CanQueenAttack(test.w, test.b)
|
||||
}
|
||||
}
|
||||
}
|
33
go/raindrops/README.md
Normal file
33
go/raindrops/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Raindrops
|
||||
|
||||
Write a program that converts a number to a string, the contents of which depends on the number's prime factors.
|
||||
|
||||
- If the number contains 3 as a prime factor, output 'Pling'.
|
||||
- If the number contains 5 as a prime factor, output 'Plang'.
|
||||
- If the number contains 7 as a prime factor, output 'Plong'.
|
||||
- If the number does not contain 3, 5, or 7 as a prime factor,
|
||||
just pass the number's digits straight through.
|
||||
|
||||
## Examples
|
||||
|
||||
- 28's prime-factorization is 2, 2, 7.
|
||||
- In raindrop-speak, this would be a simple "Plong".
|
||||
- 1755 prime-factorization is 3, 3, 3, 5, 13.
|
||||
- In raindrop-speak, this would be a "PlingPlang".
|
||||
- The prime factors of 34 are 2 and 17.
|
||||
- Raindrop-speak doesn't know what to make of that,
|
||||
so it just goes with the straightforward "34".
|
||||
|
||||
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://help.exercism.io/getting-started-with-go.html).
|
||||
|
||||
## Source
|
||||
|
||||
A variation on a famous interview question intended to weed out potential candidates. [view source](http://jumpstartlab.com)
|
25
go/raindrops/cases_test.go
Normal file
25
go/raindrops/cases_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package raindrops
|
||||
|
||||
// Source: exercism/x-common
|
||||
// Commit: 3b07e53 Merge pull request #117 from mikeyjcat/add-raindrops-json
|
||||
|
||||
var tests = []struct {
|
||||
input int
|
||||
expected string
|
||||
}{
|
||||
{1, "1"},
|
||||
{3, "Pling"},
|
||||
{5, "Plang"},
|
||||
{7, "Plong"},
|
||||
{6, "Pling"},
|
||||
{9, "Pling"},
|
||||
{10, "Plang"},
|
||||
{14, "Plong"},
|
||||
{15, "PlingPlang"},
|
||||
{21, "PlingPlong"},
|
||||
{25, "Plang"},
|
||||
{35, "PlangPlong"},
|
||||
{49, "Plong"},
|
||||
{52, "52"},
|
||||
{105, "PlingPlangPlong"},
|
||||
}
|
26
go/raindrops/raindrops.go
Normal file
26
go/raindrops/raindrops.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package raindrops
|
||||
|
||||
import "fmt"
|
||||
|
||||
// TestVersion
|
||||
const TestVersion = 1
|
||||
|
||||
// Convert takes a number and returns Raindrop-speak
|
||||
func Convert(i int) string {
|
||||
var ret string
|
||||
if i%3 == 0 {
|
||||
ret += "Pling"
|
||||
}
|
||||
if i%5 == 0 {
|
||||
ret += "Plang"
|
||||
}
|
||||
if i%7 == 0 {
|
||||
ret += "Plong"
|
||||
}
|
||||
if ret != "" {
|
||||
return ret
|
||||
}
|
||||
return fmt.Sprintf("%d", i)
|
||||
}
|
||||
|
||||
// The test program has a benchmark too. How fast does your Convert convert?
|
28
go/raindrops/raindrops_test.go
Normal file
28
go/raindrops/raindrops_test.go
Normal file
@@ -0,0 +1,28 @@
|
||||
package raindrops
|
||||
|
||||
import "testing"
|
||||
|
||||
const testVersion = 1
|
||||
|
||||
// Retired testVersions
|
||||
// (none) 52fb31c169bc1b540109028f33f4f61b5f429753
|
||||
|
||||
func TestConvert(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion)
|
||||
}
|
||||
for _, test := range tests {
|
||||
if actual := Convert(test.input); actual != test.expected {
|
||||
t.Errorf("Convert(%d) = %q, expected %q.",
|
||||
test.input, actual, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkConvert(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range tests {
|
||||
Convert(test.input)
|
||||
}
|
||||
}
|
||||
}
|
32
go/react/README.md
Normal file
32
go/react/README.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# React
|
||||
|
||||
Implement a basic reactive system.
|
||||
|
||||
Reactive programming is a programming paradigm that focuses on how values
|
||||
are computed in terms of each other to allow a change to one value to
|
||||
automatically propagate to other values, like in a spreadsheet.
|
||||
|
||||
Implement a basic reactive system with cells with settable values ("input"
|
||||
cells) and cells with values computed in terms of other cells ("compute"
|
||||
cells). Implement updates so that when an input value is changed, values
|
||||
propagate to reach a new stable system state.
|
||||
|
||||
In addition, compute cells should allow for registering change notification
|
||||
callbacks. Call a cell’s callbacks when the cell’s value in a new stable
|
||||
state has changed from the previous stable state.
|
||||
|
||||
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).
|
||||
|
||||
|
||||
|
||||
## Submitting Incomplete Problems
|
||||
It's possible to submit an incomplete solution so you can see how others have completed the exercise.
|
||||
|
49
go/react/interfaces.go
Normal file
49
go/react/interfaces.go
Normal file
@@ -0,0 +1,49 @@
|
||||
package react
|
||||
|
||||
// A Reactor manages linked cells.
|
||||
type Reactor interface {
|
||||
// CreateInput creates an input cell linked into the reactor
|
||||
// with the given initial value.
|
||||
CreateInput(int) InputCell
|
||||
|
||||
// CreateCompute1 creates a compute cell which computes its value
|
||||
// based on one other cell. The compute function will only be called
|
||||
// if the value of the passed cell changes.
|
||||
CreateCompute1(Cell, func(int) int) ComputeCell
|
||||
|
||||
// CreateCompute2 is like CreateCompute1, but depending on two cells.
|
||||
// The compute function will only be called if the value of any of the
|
||||
// passed cells changes.
|
||||
CreateCompute2(Cell, Cell, func(int, int) int) ComputeCell
|
||||
}
|
||||
|
||||
// A Cell is conceptually a holder of a value.
|
||||
type Cell interface {
|
||||
// Value returns the current value of the cell.
|
||||
Value() int
|
||||
}
|
||||
|
||||
// An InputCell has a changeable value, changing the value triggers updates to
|
||||
// other cells.
|
||||
type InputCell interface {
|
||||
Cell
|
||||
|
||||
// SetValue sets the value of the cell.
|
||||
SetValue(int)
|
||||
}
|
||||
|
||||
// A ComputeCell always computes its value based on other cells and can
|
||||
// call callbacks upon changes.
|
||||
type ComputeCell interface {
|
||||
Cell
|
||||
|
||||
// AddCallback adds a callback which will be called when the value changes.
|
||||
// It returns a callback handle which can be used to remove the callback.
|
||||
AddCallback(func(int)) CallbackHandle
|
||||
|
||||
// RemoveCallback removes a previously added callback, if it exists.
|
||||
RemoveCallback(CallbackHandle)
|
||||
}
|
||||
|
||||
// A CallbackHandle is used to remove previously added callbacks, see ComputeCell.
|
||||
type CallbackHandle interface{}
|
94
go/react/react.go
Normal file
94
go/react/react.go
Normal file
@@ -0,0 +1,94 @@
|
||||
package react
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
const testVersion = 4
|
||||
|
||||
// MyReactor implements Reactor
|
||||
type MyReactor struct {
|
||||
lastId int
|
||||
cells []Cell
|
||||
}
|
||||
|
||||
// New creates a new Reactor
|
||||
func New() *MyReactor {
|
||||
r := &MyReactor{}
|
||||
//r.callbacks = make(map[Cell][]func(int))
|
||||
return r
|
||||
}
|
||||
|
||||
// CreateInput builds an input cell and adds it to the reactor
|
||||
func (r *MyReactor) CreateInput(i int) InputCell {
|
||||
r.lastId++
|
||||
ic := MyCell{val: i, id: r.lastId}
|
||||
return &ic
|
||||
}
|
||||
|
||||
// CreateCompute1 Takes a cell and a function and returns a compute cell
|
||||
// which has a value based on running the function on the cells value.
|
||||
func (r *MyReactor) CreateCompute1(c Cell, f func(int) int) ComputeCell {
|
||||
r.lastId++
|
||||
cc := &MyCell{id: r.lastId, isComputed: true}
|
||||
cc.compVal = func() int { return f(c.Value()) }
|
||||
return cc
|
||||
}
|
||||
|
||||
// CreateCompute2 Takes two cells and a function and returns a compute cell
|
||||
// which has a value based on running the function on the cells values.
|
||||
func (r *MyReactor) CreateCompute2(c1, c2 Cell, f func(int, int) int) ComputeCell {
|
||||
r.lastId++
|
||||
cc := &MyCell{id: r.lastId, isComputed: true}
|
||||
cc.compVal = func() int { return f(c1.Value(), c2.Value()) }
|
||||
return cc
|
||||
}
|
||||
|
||||
// MyCell implements the all Cell interfaces
|
||||
type MyCell struct {
|
||||
id int
|
||||
isComputed bool
|
||||
val int
|
||||
compVal func() int
|
||||
lastCallbackId int
|
||||
callbacks map[int]func(int)
|
||||
}
|
||||
|
||||
// Value returns the value of the cell
|
||||
func (c MyCell) Value() int {
|
||||
if c.isComputed {
|
||||
return c.compVal()
|
||||
}
|
||||
return c.val
|
||||
}
|
||||
|
||||
// SetValue sets the value on the cell
|
||||
func (c *MyCell) SetValue(i int) {
|
||||
if i == c.val || c.isComputed {
|
||||
// No change or this is a computed cell, just return
|
||||
return
|
||||
}
|
||||
c.val = i
|
||||
// Hit all callbacks
|
||||
for _, v := range c.callbacks {
|
||||
fmt.Println("Hitting a callback: " + strconv.Itoa(i))
|
||||
v(i)
|
||||
}
|
||||
}
|
||||
|
||||
func (c *MyCell) AddCallback(cb func(int)) CallbackHandle {
|
||||
if c.lastCallbackId == 0 {
|
||||
fmt.Println("Initializing Callback Map (Cell " + strconv.Itoa(c.id) + ")")
|
||||
c.callbacks = make(map[int]func(int))
|
||||
}
|
||||
fmt.Println("Adding a Callback to " + strconv.Itoa(c.id))
|
||||
c.lastCallbackId++
|
||||
c.callbacks[c.lastCallbackId] = cb
|
||||
fmt.Println("Number of Callbacks: " + strconv.Itoa(c.lastCallbackId))
|
||||
return c.lastCallbackId
|
||||
}
|
||||
|
||||
func (c *MyCell) RemoveCallback(cbh CallbackHandle) {
|
||||
delete(c.callbacks, cbh.(int))
|
||||
}
|
278
go/react/react_test.go
Normal file
278
go/react/react_test.go
Normal file
@@ -0,0 +1,278 @@
|
||||
package react
|
||||
|
||||
import (
|
||||
"runtime"
|
||||
"testing"
|
||||
)
|
||||
|
||||
// Define a function New() Reactor and the stuff that follows from
|
||||
// implementing Reactor.
|
||||
//
|
||||
// Also define a testVersion with a value that matches
|
||||
// the targetTestVersion here.
|
||||
|
||||
const targetTestVersion = 4
|
||||
|
||||
// This is a compile time check to see if you've properly implemented New().
|
||||
var _ Reactor = New()
|
||||
|
||||
// If this test fails and you've proprly defined testVersion the requirements
|
||||
// of the tests have changed since you wrote your submission.
|
||||
func TestTestVersion(t *testing.T) {
|
||||
if testVersion != targetTestVersion {
|
||||
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
|
||||
}
|
||||
}
|
||||
|
||||
func assertCellValue(t *testing.T, c Cell, expected int, explanation string) {
|
||||
observed := c.Value()
|
||||
_, _, line, _ := runtime.Caller(1)
|
||||
if observed != expected {
|
||||
t.Fatalf("(from line %d) %s: expected %d, got %d", line, explanation, expected, observed)
|
||||
}
|
||||
}
|
||||
|
||||
// Setting the value of an input cell changes the observable Value()
|
||||
func TestSetInput(t *testing.T) {
|
||||
r := New()
|
||||
i := r.CreateInput(1)
|
||||
assertCellValue(t, i, 1, "i.Value() doesn't match initial value")
|
||||
i.SetValue(2)
|
||||
assertCellValue(t, i, 2, "i.Value() doesn't match changed value")
|
||||
}
|
||||
|
||||
// The value of a compute 1 cell is determined by the value of the dependencies.
|
||||
func TestBasicCompute1(t *testing.T) {
|
||||
r := New()
|
||||
i := r.CreateInput(1)
|
||||
c := r.CreateCompute1(i, func(v int) int { return v + 1 })
|
||||
assertCellValue(t, c, 2, "c.Value() isn't properly computed based on initial input cell value")
|
||||
i.SetValue(2)
|
||||
assertCellValue(t, c, 3, "c.Value() isn't properly computed based on changed input cell value")
|
||||
}
|
||||
|
||||
// The value of a compute 2 cell is determined by the value of the dependencies.
|
||||
func TestBasicCompute2(t *testing.T) {
|
||||
r := New()
|
||||
i1 := r.CreateInput(1)
|
||||
i2 := r.CreateInput(2)
|
||||
c := r.CreateCompute2(i1, i2, func(v1, v2 int) int { return v1 | v2 })
|
||||
assertCellValue(t, c, 3, "c.Value() isn't properly computed based on initial input cell values")
|
||||
i1.SetValue(4)
|
||||
assertCellValue(t, c, 6, "c.Value() isn't properly computed when first input cell value changes")
|
||||
i2.SetValue(8)
|
||||
assertCellValue(t, c, 12, "c.Value() isn't properly computed when second input cell value changes")
|
||||
}
|
||||
|
||||
// Compute 2 cells can depend on compute 1 cells.
|
||||
func TestCompute2Diamond(t *testing.T) {
|
||||
r := New()
|
||||
i := r.CreateInput(1)
|
||||
c1 := r.CreateCompute1(i, func(v int) int { return v + 1 })
|
||||
c2 := r.CreateCompute1(i, func(v int) int { return v - 1 })
|
||||
c3 := r.CreateCompute2(c1, c2, func(v1, v2 int) int { return v1 * v2 })
|
||||
assertCellValue(t, c3, 0, "c3.Value() isn't properly computed based on initial input cell value")
|
||||
i.SetValue(3)
|
||||
assertCellValue(t, c3, 8, "c3.Value() isn't properly computed based on changed input cell value")
|
||||
}
|
||||
|
||||
// Compute 1 cells can depend on other compute 1 cells.
|
||||
func TestCompute1Chain(t *testing.T) {
|
||||
r := New()
|
||||
inp := r.CreateInput(1)
|
||||
var c Cell = inp
|
||||
for i := 2; i <= 8; i++ {
|
||||
// must save current value of loop variable i for correct behavior.
|
||||
// compute function has to use digitToAdd not i.
|
||||
digitToAdd := i
|
||||
c = r.CreateCompute1(c, func(v int) int { return v*10 + digitToAdd })
|
||||
}
|
||||
assertCellValue(t, c, 12345678, "c.Value() isn't properly computed based on initial input cell value")
|
||||
inp.SetValue(9)
|
||||
assertCellValue(t, c, 92345678, "c.Value() isn't properly computed based on changed input cell value")
|
||||
}
|
||||
|
||||
// Compute 2 cells can depend on other compute 2 cells.
|
||||
func TestCompute2Tree(t *testing.T) {
|
||||
r := New()
|
||||
ins := make([]InputCell, 3)
|
||||
for i, v := range []int{1, 10, 100} {
|
||||
ins[i] = r.CreateInput(v)
|
||||
}
|
||||
|
||||
add := func(v1, v2 int) int { return v1 + v2 }
|
||||
|
||||
firstLevel := make([]ComputeCell, 2)
|
||||
for i := 0; i < 2; i++ {
|
||||
firstLevel[i] = r.CreateCompute2(ins[i], ins[i+1], add)
|
||||
}
|
||||
|
||||
output := r.CreateCompute2(firstLevel[0], firstLevel[1], add)
|
||||
assertCellValue(t, output, 121, "output.Value() isn't properly computed based on initial input cell values")
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
ins[i].SetValue(ins[i].Value() * 2)
|
||||
}
|
||||
|
||||
assertCellValue(t, output, 242, "output.Value() isn't properly computed based on changed input cell values")
|
||||
}
|
||||
|
||||
// Compute cells can have callbacks.
|
||||
func TestBasicCallback(t *testing.T) {
|
||||
r := New()
|
||||
i := r.CreateInput(1)
|
||||
c := r.CreateCompute1(i, func(v int) int { return v + 1 })
|
||||
var observed []int
|
||||
c.AddCallback(func(v int) {
|
||||
observed = append(observed, v)
|
||||
})
|
||||
if len(observed) != 0 {
|
||||
t.Fatalf("callback called before changes were made")
|
||||
}
|
||||
i.SetValue(2)
|
||||
if len(observed) != 1 {
|
||||
t.Fatalf("callback not called when changes were made")
|
||||
}
|
||||
if observed[0] != 3 {
|
||||
t.Fatalf("callback not called with proper value")
|
||||
}
|
||||
}
|
||||
|
||||
// Callbacks and only trigger on change.
|
||||
func TestOnlyCallOnChanges(t *testing.T) {
|
||||
r := New()
|
||||
i := r.CreateInput(1)
|
||||
c := r.CreateCompute1(i, func(v int) int {
|
||||
if v > 3 {
|
||||
return v + 1
|
||||
}
|
||||
return 2
|
||||
})
|
||||
var observedCalled int
|
||||
c.AddCallback(func(int) {
|
||||
observedCalled++
|
||||
})
|
||||
i.SetValue(1)
|
||||
if observedCalled != 0 {
|
||||
t.Fatalf("observe function called even though input didn't change")
|
||||
}
|
||||
i.SetValue(2)
|
||||
if observedCalled != 0 {
|
||||
t.Fatalf("observe function called even though computed value didn't change")
|
||||
}
|
||||
}
|
||||
|
||||
// Callbacks can be added and removed.
|
||||
func TestCallbackAddRemove(t *testing.T) {
|
||||
r := New()
|
||||
i := r.CreateInput(1)
|
||||
c := r.CreateCompute1(i, func(v int) int { return v + 1 })
|
||||
var observed1 []int
|
||||
cb1 := c.AddCallback(func(v int) {
|
||||
observed1 = append(observed1, v)
|
||||
})
|
||||
var observed2 []int
|
||||
c.AddCallback(func(v int) {
|
||||
observed2 = append(observed2, v)
|
||||
})
|
||||
i.SetValue(2)
|
||||
if len(observed1) != 1 || observed1[0] != 3 {
|
||||
t.Fatalf("observed1 not properly called")
|
||||
}
|
||||
if len(observed2) != 1 || observed2[0] != 3 {
|
||||
t.Fatalf("observed2 not properly called")
|
||||
}
|
||||
c.RemoveCallback(cb1)
|
||||
i.SetValue(3)
|
||||
if len(observed1) != 1 {
|
||||
t.Fatalf("observed1 called after removal")
|
||||
}
|
||||
if len(observed2) != 2 || observed2[1] != 4 {
|
||||
t.Fatalf("observed2 not properly called after first callback removal")
|
||||
}
|
||||
}
|
||||
|
||||
func TestMultipleCallbackRemoval(t *testing.T) {
|
||||
r := New()
|
||||
inp := r.CreateInput(1)
|
||||
c := r.CreateCompute1(inp, func(v int) int { return v + 1 })
|
||||
|
||||
numCallbacks := 5
|
||||
|
||||
calls := make([]int, numCallbacks)
|
||||
handles := make([]CallbackHandle, numCallbacks)
|
||||
for i := 0; i < numCallbacks; i++ {
|
||||
// Rebind i, otherwise all callbacks will use i = numCallbacks
|
||||
i := i
|
||||
handles[i] = c.AddCallback(func(v int) { calls[i]++ })
|
||||
}
|
||||
|
||||
inp.SetValue(2)
|
||||
for i := 0; i < numCallbacks; i++ {
|
||||
if calls[i] != 1 {
|
||||
t.Fatalf("callback %d/%d should be called 1 time, was called %d times", i+1, numCallbacks, calls[i])
|
||||
}
|
||||
c.RemoveCallback(handles[i])
|
||||
}
|
||||
|
||||
inp.SetValue(3)
|
||||
for i := 0; i < numCallbacks; i++ {
|
||||
if calls[i] != 1 {
|
||||
t.Fatalf("callback %d/%d was called after it was removed", i+1, numCallbacks)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveIdempotence(t *testing.T) {
|
||||
r := New()
|
||||
inp := r.CreateInput(1)
|
||||
output := r.CreateCompute1(inp, func(v int) int { return v + 1 })
|
||||
timesCalled := 0
|
||||
cb1 := output.AddCallback(func(int) {})
|
||||
output.AddCallback(func(int) { timesCalled++ })
|
||||
for i := 0; i < 10; i++ {
|
||||
output.RemoveCallback(cb1)
|
||||
}
|
||||
inp.SetValue(2)
|
||||
if timesCalled != 1 {
|
||||
t.Fatalf("remaining callback function was not called")
|
||||
}
|
||||
}
|
||||
|
||||
// Callbacks should only be called once even though
|
||||
// multiple dependencies have changed.
|
||||
func TestOnlyCallOnceOnMultipleDepChanges(t *testing.T) {
|
||||
r := New()
|
||||
i := r.CreateInput(1)
|
||||
c1 := r.CreateCompute1(i, func(v int) int { return v + 1 })
|
||||
c2 := r.CreateCompute1(i, func(v int) int { return v - 1 })
|
||||
c3 := r.CreateCompute1(c2, func(v int) int { return v - 1 })
|
||||
c4 := r.CreateCompute2(c1, c3, func(v1, v3 int) int { return v1 * v3 })
|
||||
changed4 := 0
|
||||
c4.AddCallback(func(int) { changed4++ })
|
||||
i.SetValue(3)
|
||||
if changed4 < 1 {
|
||||
t.Fatalf("callback function was not called")
|
||||
} else if changed4 > 1 {
|
||||
t.Fatalf("callback function was called too often")
|
||||
}
|
||||
}
|
||||
|
||||
// Callbacks should not be called if dependencies change in such a way
|
||||
// that the final value of the compute cell does not change.
|
||||
func TestNoCallOnDepChangesResultingInNoChange(t *testing.T) {
|
||||
r := New()
|
||||
inp := r.CreateInput(0)
|
||||
plus1 := r.CreateCompute1(inp, func(v int) int { return v + 1 })
|
||||
minus1 := r.CreateCompute1(inp, func(v int) int { return v - 1 })
|
||||
// The output's value is always 2, no matter what the input is.
|
||||
output := r.CreateCompute2(plus1, minus1, func(v1, v2 int) int { return v1 - v2 })
|
||||
|
||||
timesCalled := 0
|
||||
output.AddCallback(func(int) { timesCalled++ })
|
||||
|
||||
inp.SetValue(5)
|
||||
if timesCalled != 0 {
|
||||
t.Fatalf("callback function called even though computed value didn't change")
|
||||
}
|
||||
}
|
33
go/rna-transcription/README.md
Normal file
33
go/rna-transcription/README.md
Normal file
@@ -0,0 +1,33 @@
|
||||
# Rna Transcription
|
||||
|
||||
Write a program that, given a DNA strand, returns its RNA complement (per RNA transcription).
|
||||
|
||||
Both DNA and RNA strands are a sequence of nucleotides.
|
||||
|
||||
The four nucleotides found in DNA are adenine (**A**), cytosine (**C**),
|
||||
guanine (**G**) and thymine (**T**).
|
||||
|
||||
The four nucleotides found in RNA are adenine (**A**), cytosine (**C**),
|
||||
guanine (**G**) and uracil (**U**).
|
||||
|
||||
Given a DNA strand, its transcribed RNA strand is formed by replacing
|
||||
each nucleotide with its complement:
|
||||
|
||||
* `G` -> `C`
|
||||
* `C` -> `G`
|
||||
* `T` -> `A`
|
||||
* `A` -> `U`
|
||||
|
||||
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
|
||||
|
||||
Rosalind [view source](http://rosalind.info/problems/rna)
|
24
go/rna-transcription/cases_test.go
Normal file
24
go/rna-transcription/cases_test.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package strand
|
||||
|
||||
// Source: exercism/x-common
|
||||
// Commit: 6985644 Merge pull request #121 from mikeyjcat/add-roman-numerals-test-definition
|
||||
|
||||
var rnaTests = []struct {
|
||||
input string
|
||||
expected string
|
||||
}{
|
||||
// rna complement of cytosine is guanine
|
||||
{"C", "G"},
|
||||
|
||||
// rna complement of guanine is cytosine
|
||||
{"G", "C"},
|
||||
|
||||
// rna complement of thymine is adenine
|
||||
{"T", "A"},
|
||||
|
||||
// rna complement of adenine is uracil
|
||||
{"A", "U"},
|
||||
|
||||
// rna complement
|
||||
{"ACGTGGTCTTAA", "UGCACCAGAAUU"},
|
||||
}
|
25
go/rna-transcription/rna_transcription_test.go
Normal file
25
go/rna-transcription/rna_transcription_test.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package strand
|
||||
|
||||
import "testing"
|
||||
|
||||
const testVersion = 2
|
||||
|
||||
func TestRNATranscription(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion)
|
||||
}
|
||||
for _, test := range rnaTests {
|
||||
if actual := ToRNA(test.input); actual != test.expected {
|
||||
t.Errorf("ToRNA(%s): %s, expected %s",
|
||||
test.input, actual, test.expected)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRNATranscription(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range rnaTests {
|
||||
ToRNA(test.input)
|
||||
}
|
||||
}
|
||||
}
|
57
go/roman-numerals/README.md
Normal file
57
go/roman-numerals/README.md
Normal file
@@ -0,0 +1,57 @@
|
||||
# Roman Numerals
|
||||
|
||||
Write a function to convert from normal numbers to Roman Numerals: e.g.
|
||||
|
||||
The Romans were a clever bunch. They conquered most of Europe and ruled
|
||||
it for hundreds of years. They invented concrete and straight roads and
|
||||
even bikinis. One thing they never discovered though was the number
|
||||
zero. This made writing and dating extensive histories of their exploits
|
||||
slightly more challenging, but the system of numbers they came up with
|
||||
is still in use today. For example the BBC uses Roman numerals to date
|
||||
their programmes.
|
||||
|
||||
The Romans wrote numbers using letters - I, V, X, L, C, D, M. (notice
|
||||
these letters have lots of straight lines and are hence easy to hack
|
||||
into stone tablets).
|
||||
|
||||
```
|
||||
1 => I
|
||||
10 => X
|
||||
7 => VII
|
||||
```
|
||||
|
||||
There is no need to be able to convert numbers larger than about 3000.
|
||||
(The Romans themselves didn't tend to go any higher)
|
||||
|
||||
Wikipedia says: Modern Roman numerals ... are written by expressing each
|
||||
digit separately starting with the left most digit and skipping any
|
||||
digit with a value of zero.
|
||||
|
||||
To see this in practice, consider the example of 1990.
|
||||
|
||||
In Roman numerals 1990 is MCMXC:
|
||||
|
||||
1000=M
|
||||
900=CM
|
||||
90=XC
|
||||
|
||||
2008 is written as MMVIII:
|
||||
|
||||
2000=MM
|
||||
8=VIII
|
||||
|
||||
See also: http://www.novaroma.org/via_romana/numbers.html
|
||||
|
||||
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
|
||||
|
||||
The Roman Numeral Kata [view source](http://codingdojo.org/cgi-bin/wiki.pl?KataRomanNumerals)
|
31
go/roman-numerals/cases_test.go
Normal file
31
go/roman-numerals/cases_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package romannumerals
|
||||
|
||||
// Source: exercism/x-common
|
||||
// Commit: 6985644 Merge pull request #121 from mikeyjcat/add-roman-numerals-test-definition
|
||||
|
||||
type romanNumeralTest struct {
|
||||
arabic int
|
||||
roman string
|
||||
hasError bool
|
||||
}
|
||||
|
||||
var romanNumeralTests = []romanNumeralTest{
|
||||
{1, "I", false},
|
||||
{2, "II", false},
|
||||
{3, "III", false},
|
||||
{4, "IV", false},
|
||||
{5, "V", false},
|
||||
{6, "VI", false},
|
||||
{9, "IX", false},
|
||||
{27, "XXVII", false},
|
||||
{48, "XLVIII", false},
|
||||
{59, "LIX", false},
|
||||
{93, "XCIII", false},
|
||||
{141, "CXLI", false},
|
||||
{163, "CLXIII", false},
|
||||
{402, "CDII", false},
|
||||
{575, "DLXXV", false},
|
||||
{911, "CMXI", false},
|
||||
{1024, "MXXIV", false},
|
||||
{3000, "MMM", false},
|
||||
}
|
BIN
go/roman-numerals/cmd/cmd
Executable file
BIN
go/roman-numerals/cmd/cmd
Executable file
Binary file not shown.
22
go/roman-numerals/cmd/test.go
Normal file
22
go/roman-numerals/cmd/test.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
|
||||
"../../roman-numerals"
|
||||
)
|
||||
|
||||
func main() {
|
||||
arabic := []int{0, -1, 4000, 3999, 1, 2, 3, 4, 5, 6, 9, 27, 48, 59, 93, 141, 163, 402, 575, 911, 1024, 3000}
|
||||
for i := range arabic {
|
||||
fmt.Println(strconv.Itoa(arabic[i]) + ": ")
|
||||
if v, err := romannumerals.ToRomanNumeral(arabic[i]); err == nil {
|
||||
fmt.Print("-->")
|
||||
fmt.Println(v)
|
||||
} else {
|
||||
fmt.Print("-->")
|
||||
fmt.Println(err.Error())
|
||||
}
|
||||
}
|
||||
}
|
39
go/roman-numerals/roman_numerals_test.go
Normal file
39
go/roman-numerals/roman_numerals_test.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package romannumerals
|
||||
|
||||
import "testing"
|
||||
|
||||
const testVersion = 1
|
||||
|
||||
func TestRomanNumerals(t *testing.T) {
|
||||
if TestVersion != testVersion {
|
||||
t.Fatalf("Found TestVersion = %v, want %v", TestVersion, testVersion)
|
||||
}
|
||||
tc := append(romanNumeralTests, []romanNumeralTest{
|
||||
{0, "", true},
|
||||
{-1, "", true},
|
||||
{4000, "", true},
|
||||
{3999, "MMMCMXCIX", false},
|
||||
}...)
|
||||
for _, test := range tc {
|
||||
actual, err := ToRomanNumeral(test.arabic)
|
||||
if err == nil && test.hasError {
|
||||
t.Errorf("ToRomanNumeral(%d) should return an error.", test.arabic)
|
||||
continue
|
||||
}
|
||||
if err != nil && !test.hasError {
|
||||
t.Errorf("ToRomanNumeral(%d) should not return an error.", test.arabic)
|
||||
continue
|
||||
}
|
||||
if actual != test.roman {
|
||||
t.Errorf("ToRomanNumeral(%d): %s, expected %s", test.arabic, actual, test.roman)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkRomanNumerals(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
for _, test := range romanNumeralTests {
|
||||
ToRomanNumeral(test.arabic)
|
||||
}
|
||||
}
|
||||
}
|
72
go/roman-numerals/romannumerals.go
Normal file
72
go/roman-numerals/romannumerals.go
Normal file
@@ -0,0 +1,72 @@
|
||||
package romannumerals
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// TestVersion tells exercism which tests to use
|
||||
const TestVersion = 1
|
||||
|
||||
// ToRomanNumeral takes an int and returns it's roman numberal string value
|
||||
// Or an error if it can't be done.
|
||||
func ToRomanNumeral(arabic int) (string, error) {
|
||||
if arabic <= 0 || arabic > 3999 {
|
||||
return "", errors.New("Invalid number given")
|
||||
}
|
||||
var ret string
|
||||
var err error
|
||||
var care int
|
||||
place := 1
|
||||
for ; arabic > 0; arabic = (arabic - care) / 10 {
|
||||
care = arabic % 10
|
||||
ret = getRomanChar(care, place) + ret
|
||||
place *= 10
|
||||
}
|
||||
if strings.Contains(ret, "?") {
|
||||
err = errors.New("Invalid number given")
|
||||
}
|
||||
return ret, err
|
||||
}
|
||||
|
||||
func getRomanChar(dg, pl int) string {
|
||||
switch {
|
||||
case dg <= 0:
|
||||
return ""
|
||||
case dg < 4:
|
||||
return strings.Repeat(getOnesPlaceChar(pl), dg)
|
||||
case dg == 4:
|
||||
return getOnesPlaceChar(pl) + getFivesPlaceChar(pl)
|
||||
case dg < 9:
|
||||
return getFivesPlaceChar(pl) + getRomanChar(dg-5, pl)
|
||||
case dg == 9:
|
||||
return getOnesPlaceChar(pl) + getOnesPlaceChar(pl*10)
|
||||
}
|
||||
return "?"
|
||||
}
|
||||
|
||||
func getOnesPlaceChar(pl int) string {
|
||||
switch pl {
|
||||
case 1:
|
||||
return "I"
|
||||
case 10:
|
||||
return "X"
|
||||
case 100:
|
||||
return "C"
|
||||
case 1000:
|
||||
return "M"
|
||||
}
|
||||
return "?"
|
||||
}
|
||||
|
||||
func getFivesPlaceChar(pl int) string {
|
||||
switch pl {
|
||||
case 1:
|
||||
return "V"
|
||||
case 10:
|
||||
return "L"
|
||||
case 100:
|
||||
return "D"
|
||||
}
|
||||
return "?"
|
||||
}
|
77
go/say/README.md
Normal file
77
go/say/README.md
Normal file
@@ -0,0 +1,77 @@
|
||||
# Say
|
||||
|
||||
Write a program that will take a number from 0 to 999,999,999,999 and spell out that number in English.
|
||||
|
||||
## Step 1
|
||||
|
||||
Handle the basic case of 0 through 99.
|
||||
|
||||
If the input to the program is `22`, then the output should be
|
||||
`'twenty-two'`.
|
||||
|
||||
Your program should complain loudly if given a number outside the
|
||||
blessed range.
|
||||
|
||||
Some good test cases for this program are:
|
||||
|
||||
- 0
|
||||
- 14
|
||||
- 50
|
||||
- 98
|
||||
- -1
|
||||
- 100
|
||||
|
||||
### Extension
|
||||
|
||||
If you're on a Mac, shell out to Mac OS X's `say` program to talk out
|
||||
loud.
|
||||
|
||||
## Step 2
|
||||
|
||||
Implement breaking a number up into chunks of thousands.
|
||||
|
||||
So `1234567890` should yield a list like 1, 234, 567, and 890, while the
|
||||
far simpler `1000` should yield just 1 and 0.
|
||||
|
||||
The program must also report any values that are out of range.
|
||||
|
||||
## Step 3
|
||||
|
||||
Now handle inserting the appropriate scale word between those chunks.
|
||||
|
||||
So `1234567890` should yield `'1 billion 234 million 567 thousand 890'`
|
||||
|
||||
The program must also report any values that are out of range. It's
|
||||
fine to stop at "trillion".
|
||||
|
||||
## Step 4
|
||||
|
||||
Put it all together to get nothing but plain English.
|
||||
|
||||
`12345` should give `twelve thousand three hundred forty-five`.
|
||||
|
||||
The program must also report any values that are out of range.
|
||||
|
||||
### Extensions
|
||||
|
||||
Use _and_ (correctly) when spelling out the number in English:
|
||||
|
||||
- 14 becomes "fourteen".
|
||||
- 100 becomes "one hundred".
|
||||
- 120 becomes "one hundred and twenty".
|
||||
- 1002 becomes "one thousand and two".
|
||||
- 1323 becomes "one thousand three hundred and twenty-three".
|
||||
|
||||
To run the tests simply run the command `go test` in the exercise directory.
|
||||
|
||||
If the test suite contains benchmarks, you can run these with the `-bench`
|
||||
flag:
|
||||
|
||||
go test -bench .
|
||||
|
||||
For more detailed info about the Go track see the [help
|
||||
page](http://exercism.io/languages/go).
|
||||
|
||||
## Source
|
||||
|
||||
A variation on JavaRanch CattleDrive, exercise 4a [http://www.javaranch.com/say.jsp](http://www.javaranch.com/say.jsp)
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user