From 509c5063d66e8bbef4ec1def1c99c318be51aceb Mon Sep 17 00:00:00 2001 From: Dimitri Sokolyuk Date: Thu, 25 Aug 2016 03:13:39 +0200 Subject: Initial import --- go/bob/README.md | 48 +++++++++++++ go/bob/bob.go | 32 +++++++++ go/bob/bob_test.go | 30 ++++++++ go/bob/cases_test.go | 141 ++++++++++++++++++++++++++++++++++++ go/clock/README.md | 27 +++++++ go/clock/cases_test.go | 152 +++++++++++++++++++++++++++++++++++++++ go/clock/clock.go | 29 ++++++++ go/clock/clock_test.go | 83 +++++++++++++++++++++ go/gigasecond/README.md | 23 ++++++ go/gigasecond/cases_test.go | 31 ++++++++ go/gigasecond/gigasecond.go | 9 +++ go/gigasecond/gigasecond_test.go | 63 ++++++++++++++++ go/hamming/README.md | 54 ++++++++++++++ go/hamming/cases_test.go | 81 +++++++++++++++++++++ go/hamming/hamming.go | 18 +++++ go/hamming/hamming_test.go | 36 ++++++++++ go/hello-world/README.md | 58 +++++++++++++++ go/hello-world/hello_test.go | 29 ++++++++ go/hello-world/hello_world.go | 11 +++ go/leap/README.md | 45 ++++++++++++ go/leap/cases_test.go | 17 +++++ go/leap/leap.go | 8 +++ go/leap/leap_test.go | 32 +++++++++ go/raindrops/README.md | 37 ++++++++++ go/raindrops/cases_test.go | 25 +++++++ go/raindrops/raindrops.go | 21 ++++++ go/raindrops/raindrops_test.go | 25 +++++++ go/triangle/.triangle.go.swp | Bin 0 -> 12288 bytes go/triangle/README.md | 29 ++++++++ go/triangle/triangle.go | 17 +++++ go/triangle/triangle_test.go | 99 +++++++++++++++++++++++++ 31 files changed, 1310 insertions(+) create mode 100644 go/bob/README.md create mode 100644 go/bob/bob.go create mode 100644 go/bob/bob_test.go create mode 100644 go/bob/cases_test.go create mode 100644 go/clock/README.md create mode 100644 go/clock/cases_test.go create mode 100644 go/clock/clock.go create mode 100644 go/clock/clock_test.go create mode 100644 go/gigasecond/README.md create mode 100644 go/gigasecond/cases_test.go create mode 100644 go/gigasecond/gigasecond.go create mode 100644 go/gigasecond/gigasecond_test.go create mode 100644 go/hamming/README.md create mode 100644 go/hamming/cases_test.go create mode 100644 go/hamming/hamming.go create mode 100644 go/hamming/hamming_test.go create mode 100644 go/hello-world/README.md create mode 100644 go/hello-world/hello_test.go create mode 100644 go/hello-world/hello_world.go create mode 100644 go/leap/README.md create mode 100644 go/leap/cases_test.go create mode 100644 go/leap/leap.go create mode 100644 go/leap/leap_test.go create mode 100644 go/raindrops/README.md create mode 100644 go/raindrops/cases_test.go create mode 100644 go/raindrops/raindrops.go create mode 100644 go/raindrops/raindrops_test.go create mode 100644 go/triangle/.triangle.go.swp create mode 100644 go/triangle/README.md create mode 100644 go/triangle/triangle.go create mode 100644 go/triangle/triangle_test.go diff --git a/go/bob/README.md b/go/bob/README.md new file mode 100644 index 0000000..1ed49ff --- /dev/null +++ b/go/bob/README.md @@ -0,0 +1,48 @@ +# 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. [http://pine.fm/LearnToProgram/?Chapter=06](http://pine.fm/LearnToProgram/?Chapter=06) + +## Submitting Incomplete Problems +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + diff --git a/go/bob/bob.go b/go/bob/bob.go new file mode 100644 index 0000000..129c0aa --- /dev/null +++ b/go/bob/bob.go @@ -0,0 +1,32 @@ +package bob + +import ( + "strings" + "unicode" +) + +const testVersion = 2 + +func Hey(s string) string { + s = strings.TrimSpace(s) + var hasUpper bool + var hasLower bool + for _, r := range s { + switch { + case unicode.IsUpper(r): + hasUpper = true + case unicode.IsLower(r): + hasLower = true + } + } + switch { + case hasUpper && !hasLower: + return "Whoa, chill out!" + case strings.HasSuffix(s, "?"): + return "Sure." + case len(s) == 0: + return "Fine. Be that way!" + default: + return "Whatever." + } +} diff --git a/go/bob/bob_test.go b/go/bob/bob_test.go new file mode 100644 index 0000000..e53226d --- /dev/null +++ b/go/bob/bob_test.go @@ -0,0 +1,30 @@ +package bob + +import "testing" + +const targetTestVersion = 2 + +func TestHeyBob(t *testing.T) { + if testVersion != targetTestVersion { + t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion) + } + 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) + } + } +} diff --git a/go/bob/cases_test.go b/go/bob/cases_test.go new file mode 100644 index 0000000..825d11d --- /dev/null +++ b/go/bob/cases_test.go @@ -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!", + }, +} diff --git a/go/clock/README.md b/go/clock/README.md new file mode 100644 index 0000000..84f1f51 --- /dev/null +++ b/go/clock/README.md @@ -0,0 +1,27 @@ +# 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://exercism.io/languages/go). + +## Source + +Pairing session with Erin Drummond [https://twitter.com/ebdrummond](https://twitter.com/ebdrummond) + +## Submitting Incomplete Problems +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + diff --git a/go/clock/cases_test.go b/go/clock/cases_test.go new file mode 100644 index 0000000..3884510 --- /dev/null +++ b/go/clock/cases_test.go @@ -0,0 +1,152 @@ +package clock + +// Source: exercism/x-common +// Commit: 180638f Merge pull request #217 from ErikSchierboom/patch-2 + +// Test creating a new clock with an initial time. +var timeTests = []struct { + h, m int + want string +}{ + {8, 0, "08:00"}, // on the hour + {11, 9, "11:09"}, // past the hour + {24, 0, "00:00"}, // midnight is zero hours + {25, 0, "01:00"}, // hour rolls over + {100, 0, "04:00"}, // hour rolls over continuously + {1, 60, "02:00"}, // sixty minutes is next hour + {0, 160, "02:40"}, // minutes roll over + {0, 1723, "04:43"}, // minutes roll over continuously + {25, 160, "03:40"}, // hour and minutes roll over + {201, 3001, "11:01"}, // hour and minutes roll over continuously + {72, 8640, "00:00"}, // hour and minutes roll over to exactly midnight + {-1, 15, "23:15"}, // negative hour + {-25, 0, "23:00"}, // negative hour rolls over + {-91, 0, "05:00"}, // negative hour rolls over continuously + {1, -40, "00:20"}, // negative minutes + {1, -160, "22:20"}, // negative minutes roll over + {1, -4820, "16:40"}, // negative minutes roll over continuously + {-25, -160, "20:20"}, // negative hour and minutes both roll over + {-121, -5810, "22:10"}, // negative hour and minutes both roll over continuously +} + +// Test adding and subtracting minutes. +var addTests = []struct { + h, m, a int + want string +}{ + {10, 0, 3, "10:03"}, // add minutes + {6, 41, 0, "06:41"}, // add no minutes + {0, 45, 40, "01:25"}, // add to next hour + {10, 0, 61, "11:01"}, // add more than one hour + {0, 45, 160, "03:25"}, // add more than two hours with carry + {23, 59, 2, "00:01"}, // add across midnight + {5, 32, 1500, "06:32"}, // add more than one day (1500 min = 25 hrs) + {1, 1, 3500, "11:21"}, // add more than two days + {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 + {6, 15, -160, "03:35"}, // subtract more than two hours with borrow + {5, 32, -1500, "04:32"}, // subtract more than one day (1500 min = 25 hrs) + {2, 20, -3000, "00:20"}, // subtract more than two days +} + +// 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 with hour overflow + { + hm{10, 37}, + hm{34, 37}, + true, + }, + // clocks with hour overflow by several days + { + hm{3, 11}, + hm{99, 11}, + true, + }, + // clocks with negative hour + { + hm{22, 40}, + hm{-2, 40}, + true, + }, + // clocks with negative hour that wraps + { + hm{17, 3}, + hm{-31, 3}, + true, + }, + // clocks with negative hour that wraps multiple times + { + hm{13, 49}, + hm{-83, 49}, + true, + }, + // clocks with minute overflow + { + hm{0, 1}, + hm{0, 1441}, + true, + }, + // clocks with minute overflow by several days + { + hm{2, 2}, + hm{2, 4322}, + true, + }, + // clocks with negative minute + { + hm{2, 40}, + hm{3, -20}, + true, + }, + // clocks with negative minute that wraps + { + hm{4, 10}, + hm{5, -1490}, + true, + }, + // clocks with negative minute that wraps multiple times + { + hm{6, 15}, + hm{6, -4305}, + true, + }, + // clocks with negative hours and minutes + { + hm{7, 32}, + hm{-12, -268}, + true, + }, + // clocks with negative hours and minutes that wrap + { + hm{18, 7}, + hm{-54, -11513}, + true, + }, +} diff --git a/go/clock/clock.go b/go/clock/clock.go new file mode 100644 index 0000000..036a69b --- /dev/null +++ b/go/clock/clock.go @@ -0,0 +1,29 @@ +package clock + +import "fmt" + +const testVersion = 4 + +type Clock struct { + hour, minute int +} + +func New(hour, minute int) Clock { + for minute < 0 { + minute += 60 + hour -= 1 + } + hour += minute / 60 + for hour < 0 { + hour += 24 + } + return Clock{hour % 24, minute % 60} +} + +func (c Clock) String() string { + return fmt.Sprintf("%02d:%02d", c.hour, c.minute) +} + +func (c Clock) Add(minutes int) Clock { + return New(c.hour, c.minute+minutes) +} diff --git a/go/clock/clock_test.go b/go/clock/clock_test.go new file mode 100644 index 0000000..7642c41 --- /dev/null +++ b/go/clock/clock_test.go @@ -0,0 +1,83 @@ +package clock + +import ( + "reflect" + "testing" +) + +// Clock type API: +// +// New(hour, minute int) Clock // a "constructor" +// (Clock) String() string // a "stringer" +// (Clock) Add(minutes int) Clock +// +// The Add method 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 than pointer receivers. +// For more background on this read +// https://github.com/golang/go/wiki/CodeReviewComments#receiver-type. + +const targetTestVersion = 4 + +func TestCreateClock(t *testing.T) { + if testVersion != targetTestVersion { + t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion) + } + for _, n := range timeTests { + if got := New(n.h, n.m); got.String() != n.want { + t.Fatalf("New(%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 := New(a.h, a.m).Add(a.a); got.String() != a.want { + t.Fatalf("New(%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 := New(e.c1.h, e.c1.m) + clock2 := New(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") +} + +func BenchmarkAddMinutes(b *testing.B) { + c := New(12, 0) + b.ResetTimer() + for i := 0; i < b.N; i++ { + for _, a := range addTests { + c.Add(a.a) + } + } +} + +func BenchmarkCreateClocks(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, n := range timeTests { + New(n.h, n.m) + } + } +} diff --git a/go/gigasecond/README.md b/go/gigasecond/README.md new file mode 100644 index 0000000..788f4c0 --- /dev/null +++ b/go/gigasecond/README.md @@ -0,0 +1,23 @@ +# Gigasecond + +Write a program that calculates the moment when someone has lived for 10^9 seconds. + +A gigasecond is 10^9 (1,000,000,000) 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://exercism.io/languages/go). + +## Source + +Chapter 9 in Chris Pine's online Learn to Program tutorial. [http://pine.fm/LearnToProgram/?Chapter=09](http://pine.fm/LearnToProgram/?Chapter=09) + +## Submitting Incomplete Problems +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + diff --git a/go/gigasecond/cases_test.go b/go/gigasecond/cases_test.go new file mode 100644 index 0000000..520101b --- /dev/null +++ b/go/gigasecond/cases_test.go @@ -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", + }, +} diff --git a/go/gigasecond/gigasecond.go b/go/gigasecond/gigasecond.go new file mode 100644 index 0000000..dd3f310 --- /dev/null +++ b/go/gigasecond/gigasecond.go @@ -0,0 +1,9 @@ +package gigasecond + +import "time" + +const testVersion = 4 + +func AddGigasecond(t time.Time) time.Time { + return t.Add(1e9 * time.Second) +} diff --git a/go/gigasecond/gigasecond_test.go b/go/gigasecond/gigasecond_test.go new file mode 100644 index 0000000..96642cf --- /dev/null +++ b/go/gigasecond/gigasecond_test.go @@ -0,0 +1,63 @@ +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 targetTestVersion = 4 + +// date formats used in test data +const ( + fmtD = "2006-01-02" + fmtDT = "2006-01-02T15:04:05" +) + +func TestAddGigasecond(t *testing.T) { + if testVersion != targetTestVersion { + t.Fatalf("Found testVersion = %v, want %v.", testVersion, targetTestVersion) + } + 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 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{}) + } +} diff --git a/go/hamming/README.md b/go/hamming/README.md new file mode 100644 index 0000000..83c017d --- /dev/null +++ b/go/hamming/README.md @@ -0,0 +1,54 @@ +# 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://exercism.io/languages/go). + +## Source + +The Calculating Point Mutations problem at Rosalind [http://rosalind.info/problems/hamm/](http://rosalind.info/problems/hamm/) + +## Submitting Incomplete Problems +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + diff --git a/go/hamming/cases_test.go b/go/hamming/cases_test.go new file mode 100644 index 0000000..fc808b5 --- /dev/null +++ b/go/hamming/cases_test.go @@ -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, + }, +} diff --git a/go/hamming/hamming.go b/go/hamming/hamming.go new file mode 100644 index 0000000..88dca1e --- /dev/null +++ b/go/hamming/hamming.go @@ -0,0 +1,18 @@ +package hamming + +import "errors" + +const testVersion = 4 + +func Distance(a, b string) (int, error) { + if len(a) != len(b) { + return 0, errors.New("same length required") + } + var n int + for i := 0; i < len(a); i++ { + if a[i] != b[i] { + n++ + } + } + return n, nil +} diff --git a/go/hamming/hamming_test.go b/go/hamming/hamming_test.go new file mode 100644 index 0000000..bfee705 --- /dev/null +++ b/go/hamming/hamming_test.go @@ -0,0 +1,36 @@ +package hamming + +import "testing" + +const targetTestVersion = 4 + +func TestHamming(t *testing.T) { + if testVersion != targetTestVersion { + t.Errorf("Found testVersion = %v, want %v.", testVersion, targetTestVersion) + } + for _, tc := range testCases { + switch got, err := Distance(tc.s1, tc.s2); { + case err != nil: + var _ error = err + 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) + } + } +} diff --git a/go/hello-world/README.md b/go/hello-world/README.md new file mode 100644 index 0000000..42aa266 --- /dev/null +++ b/go/hello-world/README.md @@ -0,0 +1,58 @@ +# Hello World + +Write a function that greets the user by name, or by saying "Hello, World!" if no name is given. + +["Hello, World!"](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) is the traditional first program for beginning programming in a new language. + +**Note:** You can skip this exercise by running: + + exercism skip $LANGUAGE hello-world + +## Specification + +Write a `Hello World!` function that can greet someone given their name. +The function should return the appropriate greeting. + +For an input of "Alice", the response should be "Hello, Alice!". + +If a name is not given, the response should be "Hello, World!" + +## Test-Driven Development + +As programmers mature, they eventually want to test their code. + +Here at Exercism we simulate [Test-Driven Development](http://en.wikipedia.org/wiki/Test-driven_development) (TDD), where you write your tests before writing any functionality. The simulation comes in the form of a pre-written test suite, which will signal that you have solved the problem. + +It will also provide you with a safety net to explore other solutions without breaking the functionality. + +### A typical TDD workflow on Exercism: + +1. Run the test file and pick one test that's failing. +2. Write some code to fix the test you picked. +3. Re-run the tests to confirm the test is now passing. +4. Repeat from step 1. +5. Submit your solution (`exercism submit /path/to/file`) + +## Instructions + +Submissions are encouraged to be general, within reason. Having said that, it's also important not to over-engineer a solution. + +It's important to remember that the goal is to make code as expressive and readable as we can. However, solutions to the hello-world exercise will not be reviewed by a person, but by rikki- the robot, who will offer an encouraging word. + +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 + +This is an exercise to introduce users to using Exercism [http://en.wikipedia.org/wiki/%22Hello,_world!%22_program](http://en.wikipedia.org/wiki/%22Hello,_world!%22_program) + +## Submitting Incomplete Problems +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + diff --git a/go/hello-world/hello_test.go b/go/hello-world/hello_test.go new file mode 100644 index 0000000..3099d41 --- /dev/null +++ b/go/hello-world/hello_test.go @@ -0,0 +1,29 @@ +package hello + +import "testing" + +// Define a function HelloWorld(string) string. +// +// Also define a testVersion with a value that matches +// the targetTestVersion here. + +const targetTestVersion = 2 + +func TestHelloWorld(t *testing.T) { + tests := []struct { + name, expected string + }{ + {"", "Hello, World!"}, + {"Gopher", "Hello, Gopher!"}, + } + for _, test := range tests { + observed := HelloWorld(test.name) + if observed != test.expected { + t.Fatalf("HelloWorld(%s) = %v, want %v", test.name, observed, test.expected) + } + } + + if testVersion != targetTestVersion { + t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion) + } +} diff --git a/go/hello-world/hello_world.go b/go/hello-world/hello_world.go new file mode 100644 index 0000000..590df4e --- /dev/null +++ b/go/hello-world/hello_world.go @@ -0,0 +1,11 @@ +package hello + +const testVersion = 2 + +// HelloWorld greets the World +func HelloWorld(s string) string { + if s == "" { + s = "World" + } + return "Hello, " + s + "!" +} diff --git a/go/leap/README.md b/go/leap/README.md new file mode 100644 index 0000000..9205866 --- /dev/null +++ b/go/leap/README.md @@ -0,0 +1,45 @@ +# 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 in the Gregorian calendar 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 + +Though our exercise adopts some very simple rules, there is more to +learn! + +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://exercism.io/languages/go). + +## Source + +JavaRanch Cattle Drive, exercise 3 [http://www.javaranch.com/leap.jsp](http://www.javaranch.com/leap.jsp) + +## Submitting Incomplete Problems +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + diff --git a/go/leap/cases_test.go b/go/leap/cases_test.go new file mode 100644 index 0000000..d1af40f --- /dev/null +++ b/go/leap/cases_test.go @@ -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"}, +} diff --git a/go/leap/leap.go b/go/leap/leap.go new file mode 100644 index 0000000..75908eb --- /dev/null +++ b/go/leap/leap.go @@ -0,0 +1,8 @@ +package leap + +const testVersion = 2 + +// IsLeapYear reports if it year is a leap year +func IsLeapYear(y int) bool { + return y%4 == 0 && y%100 != 0 || y%400 == 0 +} diff --git a/go/leap/leap_test.go b/go/leap/leap_test.go new file mode 100644 index 0000000..974d79e --- /dev/null +++ b/go/leap/leap_test.go @@ -0,0 +1,32 @@ +package leap + +import "testing" + +// Define a function IsLeapYear(int) bool. +// +// Also define a testVersion with a value that matches +// the targetTestVersion here. + +const targetTestVersion = 2 + +func TestLeapYears(t *testing.T) { + if testVersion != targetTestVersion { + t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion) + } + 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) + } + } +} + +// Benchmark 400 year interval to get fair weighting of different years. +func Benchmark400(b *testing.B) { + for i := 0; i < b.N; i++ { + for y := 1600; y < 2000; y++ { + IsLeapYear(y) + } + } +} diff --git a/go/raindrops/README.md b/go/raindrops/README.md new file mode 100644 index 0000000..7cd1285 --- /dev/null +++ b/go/raindrops/README.md @@ -0,0 +1,37 @@ +# Raindrops + +Write a program that converts a number to a string, the contents of which depends on the number's factors. + +- If the number contains 3 as a factor, output 'Pling'. +- If the number contains 5 as a factor, output 'Plang'. +- If the number contains 7 as a factor, output 'Plong'. +- If the number does not contain 3, 5, or 7 as a 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://exercism.io/languages/go). + +## Source + +A variation on a famous interview question intended to weed out potential candidates. [http://jumpstartlab.com](http://jumpstartlab.com) + +## Submitting Incomplete Problems +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + diff --git a/go/raindrops/cases_test.go b/go/raindrops/cases_test.go new file mode 100644 index 0000000..e551032 --- /dev/null +++ b/go/raindrops/cases_test.go @@ -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"}, +} diff --git a/go/raindrops/raindrops.go b/go/raindrops/raindrops.go new file mode 100644 index 0000000..d692900 --- /dev/null +++ b/go/raindrops/raindrops.go @@ -0,0 +1,21 @@ +package raindrops + +import "fmt" + +const testVersion = 2 + +func Convert(n int) (s string) { + if n%3 == 0 { + s += "Pling" + } + if n%5 == 0 { + s += "Plang" + } + if n%7 == 0 { + s += "Plong" + } + if s == "" { + s = fmt.Sprint(n) + } + return +} diff --git a/go/raindrops/raindrops_test.go b/go/raindrops/raindrops_test.go new file mode 100644 index 0000000..befa699 --- /dev/null +++ b/go/raindrops/raindrops_test.go @@ -0,0 +1,25 @@ +package raindrops + +import "testing" + +const targetTestVersion = 2 + +func TestConvert(t *testing.T) { + if testVersion != targetTestVersion { + t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion) + } + 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) + } + } +} diff --git a/go/triangle/.triangle.go.swp b/go/triangle/.triangle.go.swp new file mode 100644 index 0000000..d58a2a8 Binary files /dev/null and b/go/triangle/.triangle.go.swp differ diff --git a/go/triangle/README.md b/go/triangle/README.md new file mode 100644 index 0000000..8f1485d --- /dev/null +++ b/go/triangle/README.md @@ -0,0 +1,29 @@ +# Triangle + +Write a program that can tell you if a triangle is equilateral, isosceles, or scalene. + +The program should raise an error if the triangle cannot exist. + +## Hint + +The sum of the lengths of any two sides of a triangle always exceeds or +is equal to the length of the third side, a principle known as the _triangle +inequality_. + +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 Ruby Koans triangle project, parts 1 & 2 [http://rubykoans.com](http://rubykoans.com) + +## Submitting Incomplete Problems +It's possible to submit an incomplete solution so you can see how others have completed the exercise. + diff --git a/go/triangle/triangle.go b/go/triangle/triangle.go new file mode 100644 index 0000000..7243375 --- /dev/null +++ b/go/triangle/triangle.go @@ -0,0 +1,17 @@ +package triangle + +const testVersion = 2 + +// Code this function. +func KindFromSides(a, b, c float64) Kind + +// Notice it returns this type. Pick something suitable. +type Kind + +// Pick values for the following identifiers used by the test program. +NaT // not a triangle +Equ // equilateral +Iso // isosceles +Sca // scalene + +// Organize your code for readability. diff --git a/go/triangle/triangle_test.go b/go/triangle/triangle_test.go new file mode 100644 index 0000000..4532389 --- /dev/null +++ b/go/triangle/triangle_test.go @@ -0,0 +1,99 @@ +package triangle + +import ( + "math" + "testing" +) + +const targetTestVersion = 2 + +type testCase struct { + want Kind + a, b, c float64 +} + +// basic test cases +var testData = []testCase{ + {Equ, 2, 2, 2}, // same length + {Equ, 10, 10, 10}, // a little bigger + {Iso, 3, 4, 4}, // last two sides equal + {Iso, 4, 3, 4}, // first and last sides equal + {Iso, 4, 4, 3}, // first two sides equal + {Iso, 10, 10, 2}, // again + {Iso, 2, 4, 2}, // a "triangle" that is just a line is still OK + {Sca, 3, 4, 5}, // no sides equal + {Sca, 10, 11, 12}, // again + {Sca, 5, 4, 2}, // descending order + {Sca, .4, .6, .3}, // small sides + {Sca, 1, 4, 3}, // a "triangle" that is just a line is still OK + {NaT, 0, 0, 0}, // zero length + {NaT, 3, 4, -5}, // negative length + {NaT, 1, 1, 3}, // fails triangle inequality + {NaT, 2, 5, 2}, // another + {NaT, 7, 3, 2}, // another +} + +// generate cases with NaN and Infs, append to basic cases +func init() { + nan := math.NaN() + pinf := math.Inf(1) + ninf := math.Inf(-1) + nf := make([]testCase, 4*4*4) + i := 0 + for _, a := range []float64{3, nan, pinf, ninf} { + for _, b := range []float64{4, nan, pinf, ninf} { + for _, c := range []float64{5, nan, pinf, ninf} { + nf[i] = testCase{NaT, a, b, c} + i++ + } + } + } + testData = append(testData, nf[1:]...) +} + +// Test that the kinds are not equal to each other. +// If they are equal, then TestKind will return false positives. +func TestKindsNotEqual(t *testing.T) { + kindsAndNames := []struct { + kind Kind + name string + }{ + {Equ, "Equ"}, + {Iso, "Iso"}, + {Sca, "Sca"}, + {NaT, "NaT"}, + } + + for i, pair1 := range kindsAndNames { + for j := i + 1; j < len(kindsAndNames); j++ { + pair2 := kindsAndNames[j] + if pair1.kind == pair2.kind { + t.Fatalf("%s should not be equal to %s", pair1.name, pair2.name) + } + } + } +} + +func TestKind(t *testing.T) { + for _, test := range testData { + got := KindFromSides(test.a, test.b, test.c) + if got != test.want { + t.Fatalf("Triangle with sides, %g, %g, %g = %v, want %v", + test.a, test.b, test.c, got, test.want) + } + } +} + +func TestTestVersion(t *testing.T) { + if testVersion != targetTestVersion { + t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion) + } +} + +func BenchmarkKind(b *testing.B) { + for i := 0; i < b.N; i++ { + for _, test := range testData { + KindFromSides(test.a, test.b, test.c) + } + } +} -- cgit v1.2.3