Add new exercises
This commit is contained in:
parent
83565e8467
commit
22093ac00b
31 changed files with 1528 additions and 0 deletions
33
grade-school/.exercism/config.json
Normal file
33
grade-school/.exercism/config.json
Normal file
|
@ -0,0 +1,33 @@
|
|||
{
|
||||
"blurb": "Given students' names along with the grade that they are in, create a roster for the school",
|
||||
"authors": [
|
||||
"soniakeys"
|
||||
],
|
||||
"contributors": [
|
||||
"alebaffa",
|
||||
"bitfield",
|
||||
"ekingery",
|
||||
"ferhatelmas",
|
||||
"hilary",
|
||||
"jcbwlkr",
|
||||
"kytrinyx",
|
||||
"leenipper",
|
||||
"petertseng",
|
||||
"robphoenix",
|
||||
"sebito91",
|
||||
"tleen"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"grade_school.go"
|
||||
],
|
||||
"test": [
|
||||
"grade_school_test.go"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.go"
|
||||
]
|
||||
},
|
||||
"source": "A pairing session with Phil Battos at gSchool",
|
||||
"source_url": "http://gschool.it"
|
||||
}
|
1
grade-school/.exercism/metadata.json
Normal file
1
grade-school/.exercism/metadata.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"track":"go","exercise":"grade-school","id":"82fb8c4006994852b71952494cc27a3d","url":"https://exercism.org/tracks/go/exercises/grade-school","handle":"snowyforest","is_requester":true,"auto_approve":false}
|
41
grade-school/HELP.md
Normal file
41
grade-school/HELP.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests run the command `go test` from within the exercise directory.
|
||||
|
||||
If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem`
|
||||
flags:
|
||||
|
||||
go test -v --bench . --benchmem
|
||||
|
||||
Keep in mind that each reviewer will run benchmarks on a different machine, with
|
||||
different specs, so the results from these benchmark tests may vary.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit grade_school.go` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [Go track's documentation](https://exercism.org/docs/tracks/go)
|
||||
- The [Go track's programming category on the forum](https://forum.exercism.org/c/programming/go)
|
||||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [How to Write Go Code](https://golang.org/doc/code.html)
|
||||
- [Effective Go](https://golang.org/doc/effective_go.html)
|
||||
- [Go Resources](http://golang.org/help)
|
||||
- [StackOverflow](http://stackoverflow.com/questions/tagged/go)
|
68
grade-school/README.md
Normal file
68
grade-school/README.md
Normal file
|
@ -0,0 +1,68 @@
|
|||
# Grade School
|
||||
|
||||
Welcome to Grade School on Exercism's Go Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Given students' names along with the grade that they are in, create a roster
|
||||
for the school.
|
||||
|
||||
In the end, you should be able to:
|
||||
|
||||
- Add a student's name to the roster for a grade
|
||||
- "Add Jim to grade 2."
|
||||
- "OK."
|
||||
- Get a list of all students enrolled in a grade
|
||||
- "Which students are in grade 2?"
|
||||
- "We've only got Jim just now."
|
||||
- Get a sorted list of all students in all grades. Grades should sort
|
||||
as 1, 2, 3, etc., and students within a grade should be sorted
|
||||
alphabetically by name.
|
||||
- "Who all is enrolled in school right now?"
|
||||
- "Let me think. We have
|
||||
Anna, Barb, and Charlie in grade 1,
|
||||
Alex, Peter, and Zoe in grade 2
|
||||
and Jim in grade 5.
|
||||
So the answer is: Anna, Barb, Charlie, Alex, Peter, Zoe and Jim"
|
||||
|
||||
Note that all our students only have one name. (It's a small town, what
|
||||
do you want?)
|
||||
|
||||
## 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:
|
||||
|
||||
- If you're working in a language with mutable data structures and your
|
||||
implementation allows outside code to mutate the school's internal DB
|
||||
directly, see if you can prevent this. Feel free to introduce additional
|
||||
tests.
|
||||
|
||||
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?
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @soniakeys
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @alebaffa
|
||||
- @bitfield
|
||||
- @ekingery
|
||||
- @ferhatelmas
|
||||
- @hilary
|
||||
- @jcbwlkr
|
||||
- @kytrinyx
|
||||
- @leenipper
|
||||
- @petertseng
|
||||
- @robphoenix
|
||||
- @sebito91
|
||||
- @tleen
|
||||
|
||||
### Based on
|
||||
|
||||
A pairing session with Phil Battos at gSchool - http://gschool.it
|
3
grade-school/go.mod
Normal file
3
grade-school/go.mod
Normal file
|
@ -0,0 +1,3 @@
|
|||
module school
|
||||
|
||||
go 1.16
|
19
grade-school/grade_school.go
Normal file
19
grade-school/grade_school.go
Normal file
|
@ -0,0 +1,19 @@
|
|||
package school
|
||||
|
||||
// Define the Grade and School types here.
|
||||
|
||||
func New() *School {
|
||||
panic("Please implement the New function")
|
||||
}
|
||||
|
||||
func (s *School) Add(student string, grade int) {
|
||||
panic("Please implement the Add function")
|
||||
}
|
||||
|
||||
func (s *School) Grade(level int) []string {
|
||||
panic("Please implement the Grade function")
|
||||
}
|
||||
|
||||
func (s *School) Enrollment() []Grade {
|
||||
panic("Please implement the Enrollment function")
|
||||
}
|
167
grade-school/grade_school_test.go
Normal file
167
grade-school/grade_school_test.go
Normal file
|
@ -0,0 +1,167 @@
|
|||
package school
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"math/rand"
|
||||
"strconv"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestNewSchoolIsEmpty(t *testing.T) {
|
||||
if len(New().Enrollment()) != 0 {
|
||||
t.Error("New school not empty")
|
||||
}
|
||||
}
|
||||
|
||||
func list(e []Grade) (s string) {
|
||||
for _, l := range e {
|
||||
s += fmt.Sprintln(l)
|
||||
}
|
||||
return s
|
||||
}
|
||||
|
||||
func TestAddStudent(t *testing.T) {
|
||||
exp := list([]Grade{{2, []string{"Aimee"}}})
|
||||
s := New()
|
||||
s.Add("Aimee", 2)
|
||||
got := list(s.Enrollment())
|
||||
if got != exp {
|
||||
t.Errorf(`Add Aimee level 2, got
|
||||
%sexpected:
|
||||
%s`, got, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddMoreSameGrade(t *testing.T) {
|
||||
exp := list([]Grade{{2, []string{"Blair James Paul"}}})
|
||||
s := New()
|
||||
s.Add("Blair", 2)
|
||||
s.Add("James", 2)
|
||||
s.Add("Paul", 2)
|
||||
got := list(s.Enrollment())
|
||||
if got != exp {
|
||||
t.Errorf(`Add more same grade, got
|
||||
%sexpected:
|
||||
%s`, got, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestAddDifferentGrades(t *testing.T) {
|
||||
exp := list([]Grade{
|
||||
{3, []string{"Chelsea"}},
|
||||
{7, []string{"Logan"}},
|
||||
})
|
||||
s := New()
|
||||
s.Add("Chelsea", 3)
|
||||
s.Add("Logan", 7)
|
||||
got := list(s.Enrollment())
|
||||
if got != exp {
|
||||
t.Errorf(`Add different grades, got
|
||||
%sexpected:
|
||||
%s`, got, exp)
|
||||
}
|
||||
}
|
||||
|
||||
func TestGetGrade(t *testing.T) {
|
||||
exp := []string{"Bradley", "Franklin"}
|
||||
s := New()
|
||||
s.Add("Bradley", 5)
|
||||
s.Add("Franklin", 5)
|
||||
s.Add("Jeff", 1)
|
||||
got := s.Grade(5)
|
||||
if len(got) == len(exp) {
|
||||
if got[0] == exp[0] && got[1] == exp[1] ||
|
||||
got[0] == exp[1] && got[1] == exp[0] { // accept out of order
|
||||
return
|
||||
}
|
||||
}
|
||||
t.Errorf(`Get grade, got
|
||||
%q
|
||||
expected
|
||||
%q`, got, exp)
|
||||
}
|
||||
|
||||
func TestNonExistantGrade(t *testing.T) {
|
||||
s := New()
|
||||
got := s.Grade(1)
|
||||
if len(got) != 0 {
|
||||
t.Errorf(`Get non-existent grade, got
|
||||
%q
|
||||
expected
|
||||
[]`, got)
|
||||
}
|
||||
}
|
||||
|
||||
func TestSortedEnrollment(t *testing.T) {
|
||||
exp := list([]Grade{
|
||||
{3, []string{"Kyle"}},
|
||||
{4, []string{"Christopher Jennifer"}},
|
||||
{6, []string{"Kareem"}},
|
||||
})
|
||||
s := New()
|
||||
s.Add("Jennifer", 4)
|
||||
s.Add("Kareem", 6)
|
||||
s.Add("Christopher", 4)
|
||||
s.Add("Kyle", 3)
|
||||
got := list(s.Enrollment())
|
||||
if got != exp {
|
||||
t.Errorf(`Sorted enrollment, got
|
||||
%sexpected:
|
||||
%s`, got, exp)
|
||||
}
|
||||
}
|
||||
|
||||
const (
|
||||
minLevel = 1
|
||||
maxLevel = 9
|
||||
enrollment = 400
|
||||
)
|
||||
|
||||
func BenchmarkAddStudents(b *testing.B) {
|
||||
if testing.Short() {
|
||||
b.Skip("skipping benchmark in short mode.")
|
||||
}
|
||||
const pool = 1e6 // pool of students
|
||||
names := make([]string, pool)
|
||||
levels := make([]int, pool)
|
||||
for i := range names {
|
||||
names[i] = strconv.Itoa(rand.Intn(1e5))
|
||||
levels[i] = minLevel + rand.Intn(maxLevel-minLevel+1)
|
||||
}
|
||||
p := 0
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// bench combined time to create a school and add
|
||||
// a number of students, drawn from a pool of students
|
||||
s := New()
|
||||
for t := 0; t < enrollment; t++ {
|
||||
s.Add(names[p], levels[p])
|
||||
p = (p + 1) % pool
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func BenchmarkEnrollment(b *testing.B) {
|
||||
if testing.Short() {
|
||||
b.Skip("skipping benchmark in short mode.")
|
||||
}
|
||||
const pool = 1000 // pool of schools
|
||||
ss := make([]*School, pool)
|
||||
for i := range ss {
|
||||
s := New()
|
||||
for t := 0; t < enrollment; t++ {
|
||||
s.Add(
|
||||
strconv.Itoa(rand.Intn(1e5)),
|
||||
minLevel+rand.Intn(maxLevel-minLevel+1))
|
||||
}
|
||||
ss[i] = s
|
||||
}
|
||||
p := 0
|
||||
b.ResetTimer()
|
||||
for i := 0; i < b.N; i++ {
|
||||
// bench time to get enrollment of a full school,
|
||||
// averaged over a pool of schools.
|
||||
ss[p].Enrollment()
|
||||
p = (p + 1) % pool
|
||||
}
|
||||
}
|
27
party-robot/.exercism/config.json
Normal file
27
party-robot/.exercism/config.json
Normal file
|
@ -0,0 +1,27 @@
|
|||
{
|
||||
"authors": [
|
||||
"tehsphinx"
|
||||
],
|
||||
"contributors": [
|
||||
"oanaOM",
|
||||
"bobtfish"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"party_robot.go"
|
||||
],
|
||||
"test": [
|
||||
"party_robot_test.go"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.go"
|
||||
],
|
||||
"invalidator": [
|
||||
"go.mod"
|
||||
]
|
||||
},
|
||||
"blurb": "Learn about strings by programming a party robot.",
|
||||
"custom": {
|
||||
"taskIdsEnabled": true
|
||||
}
|
||||
}
|
1
party-robot/.exercism/metadata.json
Normal file
1
party-robot/.exercism/metadata.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"track":"go","exercise":"party-robot","id":"03cbe7fc829e45b486afb3ed609f932a","url":"https://exercism.org/tracks/go/exercises/party-robot","handle":"snowyforest","is_requester":true,"auto_approve":false}
|
41
party-robot/HELP.md
Normal file
41
party-robot/HELP.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests run the command `go test` from within the exercise directory.
|
||||
|
||||
If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem`
|
||||
flags:
|
||||
|
||||
go test -v --bench . --benchmem
|
||||
|
||||
Keep in mind that each reviewer will run benchmarks on a different machine, with
|
||||
different specs, so the results from these benchmark tests may vary.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit party_robot.go` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [Go track's documentation](https://exercism.org/docs/tracks/go)
|
||||
- The [Go track's programming category on the forum](https://forum.exercism.org/c/programming/go)
|
||||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [How to Write Go Code](https://golang.org/doc/code.html)
|
||||
- [Effective Go](https://golang.org/doc/effective_go.html)
|
||||
- [Go Resources](http://golang.org/help)
|
||||
- [StackOverflow](http://stackoverflow.com/questions/tagged/go)
|
27
party-robot/HINTS.md
Normal file
27
party-robot/HINTS.md
Normal file
|
@ -0,0 +1,27 @@
|
|||
# Hints
|
||||
|
||||
## General
|
||||
|
||||
- The `fmt` package of the standard library has some [formatting functionality for strings][fmt-package].
|
||||
- There is a way to [concatenate strings][string-concatenation].
|
||||
|
||||
## 1. Welcome a new guest to the party
|
||||
|
||||
- `fmt.Sprintf` lets you use a [template to create a string][sprintf].
|
||||
|
||||
## 2. Welcome a new guest to the party whose birthday is today
|
||||
|
||||
- `fmt.Sprintf` can interpolate [more than one value into your string][sprintf-multiple-values]!
|
||||
|
||||
## 3. Give directions
|
||||
|
||||
- You can use [newline characters in your string][string-newline].
|
||||
- Padding with zeroes could be achieved with one of the [formatting verbs][formatting-verbs].
|
||||
- The shorthand assignment operator `+=` can help you build up your result via string concatenation.
|
||||
|
||||
[fmt-package]: https://golang.org/pkg/fmt/
|
||||
[string-concatenation]: https://golang.org/ref/spec#String_concatenation
|
||||
[sprintf]: https://pkg.go.dev/fmt#Sprintf
|
||||
[sprintf-multiple-values]: https://www.geeksforgeeks.org/fmt-sprintf-function-in-golang-with-examples/
|
||||
[string-newline]: https://yourbasic.org/golang/multiline-string/#interpreted-string-literals
|
||||
[formatting-verbs]: https://yourbasic.org/golang/fmt-printf-reference-cheat-sheet/#cheat-sheet
|
145
party-robot/README.md
Normal file
145
party-robot/README.md
Normal file
|
@ -0,0 +1,145 @@
|
|||
# Party Robot
|
||||
|
||||
Welcome to Party Robot on Exercism's Go Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||||
|
||||
## Introduction
|
||||
|
||||
## Packages
|
||||
|
||||
In Go an application is organized in packages.
|
||||
A package is a collection of source files located in the same folder.
|
||||
All source files in a folder must have the same package name at the top of the file.
|
||||
By convention packages are named to be the same as the folder they are located in.
|
||||
|
||||
```go
|
||||
package greeting
|
||||
```
|
||||
|
||||
Go provides an extensive standard library of packages which you can use in your program using the `import` keyword.
|
||||
Standard library packages are imported using their name.
|
||||
|
||||
```go
|
||||
package greeting
|
||||
|
||||
import "fmt"
|
||||
```
|
||||
|
||||
An imported package is then addressed with the package name:
|
||||
|
||||
```go
|
||||
world := "World"
|
||||
fmt.Sprintf("Hello %s", world)
|
||||
```
|
||||
|
||||
Go determines if an item can be called by code in other packages through how it is declared.
|
||||
To make a function, type, variable, constant or struct field externally visible (known as _exported_) the name must start with a capital letter.
|
||||
|
||||
```go
|
||||
package greeting
|
||||
|
||||
// Hello is a public function (callable from other packages).
|
||||
func Hello(name string) string {
|
||||
return "Hello " + name
|
||||
}
|
||||
|
||||
// hello is a private function (not callable from other packages).
|
||||
func hello(name string) string {
|
||||
return "Hello " + name
|
||||
}
|
||||
```
|
||||
|
||||
## String Formatting
|
||||
|
||||
Go provides an in-built package called `fmt` (format package) which offers a variety of functions to manipulate the format of input and output.
|
||||
The most commonly used function is `Sprintf`, which uses verbs like `%s` to interpolate values into a string and returns that string.
|
||||
|
||||
```go
|
||||
import "fmt"
|
||||
|
||||
food := "taco"
|
||||
fmt.Sprintf("Bring me a %s", food)
|
||||
// Returns: Bring me a taco
|
||||
```
|
||||
|
||||
In Go floating point values are conveniently formatted with Sprintf's verbs: `%g` (compact representation), `%e` (exponent) or `%f` (non exponent).
|
||||
All three verbs allow the field's width and numeric position to be controlled.
|
||||
|
||||
```go
|
||||
import "fmt"
|
||||
|
||||
number := 4.3242
|
||||
fmt.Sprintf("%.2f", number)
|
||||
// Returns: 4.32
|
||||
```
|
||||
|
||||
You can find a full list of available verbs in the [format package documentation][fmt-docs].
|
||||
|
||||
`fmt` contains other functions for working with strings, such as `Println` which simply prints the arguments it receives to the console and `Printf` which formats the input in the same way as `Sprintf` before printing it.
|
||||
|
||||
[fmt-docs]: https://pkg.go.dev/fmt
|
||||
|
||||
## Instructions
|
||||
|
||||
Once there was an eccentric programmer living in a strange house with barred windows.
|
||||
One day he accepted a job from an online job board to build a party robot. The
|
||||
robot is supposed to greet people and help them to their seats. The first edition
|
||||
was very technical and showed the programmer's lack of human interaction. Some of
|
||||
which also made it into the next edition.
|
||||
|
||||
## 1. Welcome a new guest to the party
|
||||
|
||||
Implement the `Welcome` function to return a welcome message using the given name:
|
||||
|
||||
```go
|
||||
Welcome("Christiane")
|
||||
// => Welcome to my party, Christiane!
|
||||
```
|
||||
|
||||
## 2. Welcome a new guest to the party whose birthday is today
|
||||
|
||||
Implement the `HappyBirthday` function to return a birthday message using the given name and age of the person.
|
||||
Unfortunately the programmer is a bit of a show-off, so the robot has to demonstrate its knowledge of every guest's birthday.
|
||||
|
||||
```go
|
||||
HappyBirthday("Frank", 58)
|
||||
// => Happy birthday Frank! You are now 58 years old!
|
||||
```
|
||||
|
||||
## 3. Give directions
|
||||
|
||||
Implement the `AssignTable` function to give directions.
|
||||
It should accept 5 parameters.
|
||||
|
||||
- The name of the new guest to greet (`string`)
|
||||
- The table number (`int`)
|
||||
- The name of the seatmate (`string`)
|
||||
- The direction where to find the table (`string`)
|
||||
- The distance to the table (`float64`)
|
||||
|
||||
The exact result format can be seen in the example below.
|
||||
|
||||
The robot provides the table number in a 3 digits format.
|
||||
If the number is less than 3 digits it gets extra leading zeroes to become 3 digits (e.g. 3 becomes 003).
|
||||
The robot also mentions the distance of the table.
|
||||
Fortunately only with a precision that's limited to 1 digit.
|
||||
|
||||
```go
|
||||
AssignTable("Christiane", 27, "Frank", "on the left", 23.7834298)
|
||||
// =>
|
||||
// Welcome to my party, Christiane!
|
||||
// You have been assigned to table 027. Your table is on the left, exactly 23.8 meters from here.
|
||||
// You will be sitting next to Frank.
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @tehsphinx
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @oanaOM
|
||||
- @bobtfish
|
3
party-robot/go.mod
Normal file
3
party-robot/go.mod
Normal file
|
@ -0,0 +1,3 @@
|
|||
module partyrobot
|
||||
|
||||
go 1.18
|
16
party-robot/party_robot.go
Normal file
16
party-robot/party_robot.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package partyrobot
|
||||
|
||||
// Welcome greets a person by name.
|
||||
func Welcome(name string) string {
|
||||
panic("Please implement the Welcome function")
|
||||
}
|
||||
|
||||
// HappyBirthday wishes happy birthday to the birthday person and exclaims their age.
|
||||
func HappyBirthday(name string, age int) string {
|
||||
panic("Please implement the HappyBirthday function")
|
||||
}
|
||||
|
||||
// AssignTable assigns a table to each guest.
|
||||
func AssignTable(name string, table int, neighbor, direction string, distance float64) string {
|
||||
panic("Please implement the AssignTable function")
|
||||
}
|
133
party-robot/party_robot_test.go
Normal file
133
party-robot/party_robot_test.go
Normal file
|
@ -0,0 +1,133 @@
|
|||
package partyrobot
|
||||
|
||||
import (
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestWelcome(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
name string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
description: "Greet Chihiro with a welcoming message",
|
||||
name: "Chihiro",
|
||||
want: "Welcome to my party, Chihiro!",
|
||||
},
|
||||
{
|
||||
description: "Greet Xuân Jing with a welcoming message",
|
||||
name: "Xuân Jing",
|
||||
want: "Welcome to my party, Xuân Jing!",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
if got := Welcome(tt.name); got != tt.want {
|
||||
t.Errorf("Welcome(%s) = %s, want %s", tt.name, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestHappyBirthday(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
name string
|
||||
age int
|
||||
want string
|
||||
}{
|
||||
{
|
||||
description: "Wish Chihiro Happy Birthday with name and age",
|
||||
name: "Chihiro",
|
||||
age: 61,
|
||||
want: "Happy birthday Chihiro! You are now 61 years old!",
|
||||
},
|
||||
{
|
||||
description: "Wish Xuân Jing Happy Birthday with name and age",
|
||||
name: "Xuân Jing",
|
||||
age: 17,
|
||||
want: "Happy birthday Xuân Jing! You are now 17 years old!",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
if got := HappyBirthday(tt.name, tt.age); got != tt.want {
|
||||
t.Errorf("HappyBirthday(%s, %d) = %s, want %s", tt.name, tt.age, got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAssignTable(t *testing.T) {
|
||||
tests := []struct {
|
||||
description string
|
||||
name string
|
||||
direction string
|
||||
tableNumber int
|
||||
distance float64
|
||||
seatmate string
|
||||
want string
|
||||
}{
|
||||
{
|
||||
description: "Greet Chihiro and give them directions to their seat",
|
||||
name: "Chihiro",
|
||||
direction: "straight ahead",
|
||||
tableNumber: 22,
|
||||
distance: 9.2394381,
|
||||
seatmate: "Akachi Chikondi",
|
||||
want: "Welcome to my party, Chihiro!\nYou have been assigned to table 022. Your table is straight ahead, exactly 9.2 meters from here.\nYou will be sitting next to Akachi Chikondi.",
|
||||
},
|
||||
{
|
||||
description: "Greet Xuân Jing and give them directions to their seat",
|
||||
name: "Xuân Jing",
|
||||
direction: "by the façade",
|
||||
tableNumber: 4,
|
||||
distance: 23.470103,
|
||||
seatmate: "Renée",
|
||||
want: "Welcome to my party, Xuân Jing!\nYou have been assigned to table 004. Your table is by the façade, exactly 23.5 meters from here.\nYou will be sitting next to Renée.",
|
||||
},
|
||||
{
|
||||
description: "Greet Paula and give them directions to their seat",
|
||||
name: "Paula",
|
||||
direction: "on the right",
|
||||
tableNumber: 101,
|
||||
distance: 100.0,
|
||||
seatmate: "Chioma",
|
||||
want: "Welcome to my party, Paula!\nYou have been assigned to table 101. Your table is on the right, exactly 100.0 meters from here.\nYou will be sitting next to Chioma.",
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.description, func(t *testing.T) {
|
||||
if got := AssignTable(tt.name, tt.tableNumber, tt.seatmate, tt.direction, tt.distance); got != tt.want {
|
||||
t.Errorf(`AssignTable(%s,%d,%s,%s,%f)
|
||||
got:
|
||||
%q
|
||||
want:
|
||||
%q`,
|
||||
tt.name, tt.tableNumber, tt.seatmate, tt.direction, tt.distance, got, tt.want)
|
||||
|
||||
wantLen := len(tt.want)
|
||||
gotLen := len(got)
|
||||
wantNewlines := strings.Count(tt.want, "\n")
|
||||
gotNewlines := strings.Count(got, "\n")
|
||||
wantSpaces := strings.Count(tt.want, " ")
|
||||
gotSpaces := strings.Count(got, " ")
|
||||
|
||||
if wantLen != gotLen {
|
||||
t.Errorf("String lengths do not match - got: %d, want: %d", gotLen, wantLen)
|
||||
}
|
||||
|
||||
if wantNewlines != gotNewlines {
|
||||
t.Errorf("Check your newline characters - got: %d, want: %d", gotNewlines, wantNewlines)
|
||||
}
|
||||
|
||||
if wantSpaces != gotSpaces {
|
||||
t.Errorf("Check your space characters - got: %d, want: %d", gotSpaces, wantSpaces)
|
||||
}
|
||||
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
39
variable-length-quantity/.exercism/config.json
Normal file
39
variable-length-quantity/.exercism/config.json
Normal file
|
@ -0,0 +1,39 @@
|
|||
{
|
||||
"blurb": "Implement variable length quantity encoding and decoding.",
|
||||
"authors": [
|
||||
"mattetti"
|
||||
],
|
||||
"contributors": [
|
||||
"alebaffa",
|
||||
"bitfield",
|
||||
"ekingery",
|
||||
"ferhatelmas",
|
||||
"hilary",
|
||||
"ilmanzo",
|
||||
"jbsmith7741",
|
||||
"kytrinyx",
|
||||
"leenipper",
|
||||
"lfritz",
|
||||
"Ngo-The-Trung",
|
||||
"petertseng",
|
||||
"robphoenix",
|
||||
"sebito91",
|
||||
"voroskoi"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"variable_length_quantity.go"
|
||||
],
|
||||
"test": [
|
||||
"variable_length_quantity_test.go"
|
||||
],
|
||||
"example": [
|
||||
".meta/example.go"
|
||||
],
|
||||
"editor": [
|
||||
"cases_test.go"
|
||||
]
|
||||
},
|
||||
"source": "A poor Splice developer having to implement MIDI encoding/decoding.",
|
||||
"source_url": "https://splice.com"
|
||||
}
|
1
variable-length-quantity/.exercism/metadata.json
Normal file
1
variable-length-quantity/.exercism/metadata.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"track":"go","exercise":"variable-length-quantity","id":"539eb9544eff4087b4e743a21d087330","url":"https://exercism.org/tracks/go/exercises/variable-length-quantity","handle":"snowyforest","is_requester":true,"auto_approve":false}
|
41
variable-length-quantity/HELP.md
Normal file
41
variable-length-quantity/HELP.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests run the command `go test` from within the exercise directory.
|
||||
|
||||
If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem`
|
||||
flags:
|
||||
|
||||
go test -v --bench . --benchmem
|
||||
|
||||
Keep in mind that each reviewer will run benchmarks on a different machine, with
|
||||
different specs, so the results from these benchmark tests may vary.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit variable_length_quantity.go` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [Go track's documentation](https://exercism.org/docs/tracks/go)
|
||||
- The [Go track's programming category on the forum](https://forum.exercism.org/c/programming/go)
|
||||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [How to Write Go Code](https://golang.org/doc/code.html)
|
||||
- [Effective Go](https://golang.org/doc/effective_go.html)
|
||||
- [Go Resources](http://golang.org/help)
|
||||
- [StackOverflow](http://stackoverflow.com/questions/tagged/go)
|
65
variable-length-quantity/README.md
Normal file
65
variable-length-quantity/README.md
Normal file
|
@ -0,0 +1,65 @@
|
|||
# Variable Length Quantity
|
||||
|
||||
Welcome to Variable Length Quantity on Exercism's Go Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
|
||||
## Instructions
|
||||
|
||||
Implement variable length quantity encoding and decoding.
|
||||
|
||||
The goal of this exercise is to implement [VLQ](https://en.wikipedia.org/wiki/Variable-length_quantity) encoding/decoding.
|
||||
|
||||
In short, the goal of this encoding is to encode integer values in a way that would save bytes.
|
||||
Only the first 7 bits of each byte is significant (right-justified; sort of like an ASCII byte).
|
||||
So, if you have a 32-bit value, you have to unpack it into a series of 7-bit bytes.
|
||||
Of course, you will have a variable number of bytes depending upon your integer.
|
||||
To indicate which is the last byte of the series, you leave bit #7 clear.
|
||||
In all of the preceding bytes, you set bit #7.
|
||||
|
||||
So, if an integer is between `0-127`, it can be represented as one byte.
|
||||
Although VLQ can deal with numbers of arbitrary sizes, for this exercise we will restrict ourselves to only numbers that fit in a 32-bit unsigned integer.
|
||||
Here are examples of integers as 32-bit values, and the variable length quantities that they translate to:
|
||||
|
||||
```text
|
||||
NUMBER VARIABLE QUANTITY
|
||||
00000000 00
|
||||
00000040 40
|
||||
0000007F 7F
|
||||
00000080 81 00
|
||||
00002000 C0 00
|
||||
00003FFF FF 7F
|
||||
00004000 81 80 00
|
||||
00100000 C0 80 00
|
||||
001FFFFF FF FF 7F
|
||||
00200000 81 80 80 00
|
||||
08000000 C0 80 80 00
|
||||
0FFFFFFF FF FF FF 7F
|
||||
```
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @mattetti
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @alebaffa
|
||||
- @bitfield
|
||||
- @ekingery
|
||||
- @ferhatelmas
|
||||
- @hilary
|
||||
- @ilmanzo
|
||||
- @jbsmith7741
|
||||
- @kytrinyx
|
||||
- @leenipper
|
||||
- @lfritz
|
||||
- @Ngo-The-Trung
|
||||
- @petertseng
|
||||
- @robphoenix
|
||||
- @sebito91
|
||||
- @voroskoi
|
||||
|
||||
### Based on
|
||||
|
||||
A poor Splice developer having to implement MIDI encoding/decoding. - https://splice.com
|
161
variable-length-quantity/cases_test.go
Normal file
161
variable-length-quantity/cases_test.go
Normal file
|
@ -0,0 +1,161 @@
|
|||
package variablelengthquantity
|
||||
|
||||
// Source: exercism/problem-specifications
|
||||
// Commit: 191f8086 variable-length-quantity: add mention of 'error' to comment
|
||||
// Problem Specifications Version: 1.2.0
|
||||
|
||||
// Encode a series of integers, producing a series of bytes.
|
||||
var encodeTestCases = []struct {
|
||||
description string
|
||||
input []uint32
|
||||
output []byte
|
||||
}{
|
||||
{
|
||||
"zero",
|
||||
[]uint32{0x0},
|
||||
[]byte{0x0},
|
||||
},
|
||||
{
|
||||
"arbitrary single byte",
|
||||
[]uint32{0x40},
|
||||
[]byte{0x40},
|
||||
},
|
||||
{
|
||||
"largest single byte",
|
||||
[]uint32{0x7f},
|
||||
[]byte{0x7f},
|
||||
},
|
||||
{
|
||||
"smallest double byte",
|
||||
[]uint32{0x80},
|
||||
[]byte{0x81, 0x0},
|
||||
},
|
||||
{
|
||||
"arbitrary double byte",
|
||||
[]uint32{0x2000},
|
||||
[]byte{0xc0, 0x0},
|
||||
},
|
||||
{
|
||||
"largest double byte",
|
||||
[]uint32{0x3fff},
|
||||
[]byte{0xff, 0x7f},
|
||||
},
|
||||
{
|
||||
"smallest triple byte",
|
||||
[]uint32{0x4000},
|
||||
[]byte{0x81, 0x80, 0x0},
|
||||
},
|
||||
{
|
||||
"arbitrary triple byte",
|
||||
[]uint32{0x100000},
|
||||
[]byte{0xc0, 0x80, 0x0},
|
||||
},
|
||||
{
|
||||
"largest triple byte",
|
||||
[]uint32{0x1fffff},
|
||||
[]byte{0xff, 0xff, 0x7f},
|
||||
},
|
||||
{
|
||||
"smallest quadruple byte",
|
||||
[]uint32{0x200000},
|
||||
[]byte{0x81, 0x80, 0x80, 0x0},
|
||||
},
|
||||
{
|
||||
"arbitrary quadruple byte",
|
||||
[]uint32{0x8000000},
|
||||
[]byte{0xc0, 0x80, 0x80, 0x0},
|
||||
},
|
||||
{
|
||||
"largest quadruple byte",
|
||||
[]uint32{0xfffffff},
|
||||
[]byte{0xff, 0xff, 0xff, 0x7f},
|
||||
},
|
||||
{
|
||||
"smallest quintuple byte",
|
||||
[]uint32{0x10000000},
|
||||
[]byte{0x81, 0x80, 0x80, 0x80, 0x0},
|
||||
},
|
||||
{
|
||||
"arbitrary quintuple byte",
|
||||
[]uint32{0xff000000},
|
||||
[]byte{0x8f, 0xf8, 0x80, 0x80, 0x0},
|
||||
},
|
||||
{
|
||||
"maximum 32-bit integer input",
|
||||
[]uint32{0xffffffff},
|
||||
[]byte{0x8f, 0xff, 0xff, 0xff, 0x7f},
|
||||
},
|
||||
{
|
||||
"two single-byte values",
|
||||
[]uint32{0x40, 0x7f},
|
||||
[]byte{0x40, 0x7f},
|
||||
},
|
||||
{
|
||||
"two multi-byte values",
|
||||
[]uint32{0x4000, 0x123456},
|
||||
[]byte{0x81, 0x80, 0x0, 0xc8, 0xe8, 0x56},
|
||||
},
|
||||
{
|
||||
"many multi-byte values",
|
||||
[]uint32{0x2000, 0x123456, 0xfffffff, 0x0, 0x3fff, 0x4000},
|
||||
[]byte{0xc0, 0x0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x0, 0xff, 0x7f, 0x81, 0x80, 0x0},
|
||||
},
|
||||
}
|
||||
|
||||
// Decode a series of bytes, producing a series of integers.
|
||||
var decodeTestCases = []struct {
|
||||
description string
|
||||
input []byte
|
||||
output []uint32 // nil slice indicates error expected.
|
||||
errorExpected bool
|
||||
}{
|
||||
|
||||
{
|
||||
"one byte",
|
||||
[]byte{0x7f},
|
||||
[]uint32{0x7f},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"two bytes",
|
||||
[]byte{0xc0, 0x0},
|
||||
[]uint32{0x2000},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"three bytes",
|
||||
[]byte{0xff, 0xff, 0x7f},
|
||||
[]uint32{0x1fffff},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"four bytes",
|
||||
[]byte{0x81, 0x80, 0x80, 0x0},
|
||||
[]uint32{0x200000},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"maximum 32-bit integer",
|
||||
[]byte{0x8f, 0xff, 0xff, 0xff, 0x7f},
|
||||
[]uint32{0xffffffff},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"incomplete sequence causes error",
|
||||
[]byte{0xff},
|
||||
[]uint32{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"incomplete sequence causes error, even if value is zero",
|
||||
[]byte{0x80},
|
||||
[]uint32{},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"multiple values",
|
||||
[]byte{0xc0, 0x0, 0xc8, 0xe8, 0x56, 0xff, 0xff, 0xff, 0x7f, 0x0, 0xff, 0x7f, 0x81, 0x80, 0x0},
|
||||
[]uint32{0x2000, 0x123456, 0xfffffff, 0x0, 0x3fff, 0x4000},
|
||||
false,
|
||||
},
|
||||
}
|
3
variable-length-quantity/go.mod
Normal file
3
variable-length-quantity/go.mod
Normal file
|
@ -0,0 +1,3 @@
|
|||
module variablelengthquantity
|
||||
|
||||
go 1.16
|
9
variable-length-quantity/variable_length_quantity.go
Normal file
9
variable-length-quantity/variable_length_quantity.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
package variablelengthquantity
|
||||
|
||||
func EncodeVarint(input []uint32) []byte {
|
||||
panic("Please implement the EncodeVarint function")
|
||||
}
|
||||
|
||||
func DecodeVarint(input []byte) ([]uint32, error) {
|
||||
panic("Please implement the EncodeVarint function")
|
||||
}
|
34
variable-length-quantity/variable_length_quantity_test.go
Normal file
34
variable-length-quantity/variable_length_quantity_test.go
Normal file
|
@ -0,0 +1,34 @@
|
|||
package variablelengthquantity
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestDecodeVarint(t *testing.T) {
|
||||
for i, tc := range decodeTestCases {
|
||||
o, err := DecodeVarint(tc.input)
|
||||
switch {
|
||||
case err != nil:
|
||||
var _ error = err // check if err is of error type
|
||||
if !tc.errorExpected {
|
||||
t.Fatalf("FAIL: case %d | %s\nexpected %#v got error: %q\n", i, tc.description, tc.output, err)
|
||||
}
|
||||
case tc.errorExpected && err == nil:
|
||||
t.Fatalf("FAIL: case %d | %s\nexpected error, got %#v\n", i, tc.description, err)
|
||||
case !reflect.DeepEqual(o, tc.output):
|
||||
t.Fatalf("FAIL: case %d | %s\nexpected\t%#v\ngot\t\t%#v\n", i, tc.description, tc.output, o)
|
||||
}
|
||||
t.Logf("PASS: case %d | %s\n", i, tc.description)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEncodeVarint(t *testing.T) {
|
||||
for i, tc := range encodeTestCases {
|
||||
if encoded := EncodeVarint(tc.input); !bytes.Equal(encoded, tc.output) {
|
||||
t.Fatalf("FAIL: case %d | %s\nexpected\t%#v\ngot\t\t%#v\n", i, tc.description, tc.output, encoded)
|
||||
}
|
||||
t.Logf("PASS: case %d | %s\n", i, tc.description)
|
||||
}
|
||||
}
|
26
vehicle-purchase/.exercism/config.json
Normal file
26
vehicle-purchase/.exercism/config.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"authors": [
|
||||
"kahgoh"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"vehicle_purchase.go"
|
||||
],
|
||||
"test": [
|
||||
"vehicle_purchase_test.go"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.go"
|
||||
],
|
||||
"invalidator": [
|
||||
"go.mod"
|
||||
]
|
||||
},
|
||||
"forked_from": [
|
||||
"javascript/vehicle-purchase"
|
||||
],
|
||||
"blurb": "Learn about comparison and conditional-ifs while preparing for your next vehicle purchase",
|
||||
"custom": {
|
||||
"taskIdsEnabled": true
|
||||
}
|
||||
}
|
1
vehicle-purchase/.exercism/metadata.json
Normal file
1
vehicle-purchase/.exercism/metadata.json
Normal file
|
@ -0,0 +1 @@
|
|||
{"track":"go","exercise":"vehicle-purchase","id":"385ca35d7d7b4e44b20f342e5663fe0c","url":"https://exercism.org/tracks/go/exercises/vehicle-purchase","handle":"snowyforest","is_requester":true,"auto_approve":false}
|
41
vehicle-purchase/HELP.md
Normal file
41
vehicle-purchase/HELP.md
Normal file
|
@ -0,0 +1,41 @@
|
|||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests run the command `go test` from within the exercise directory.
|
||||
|
||||
If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem`
|
||||
flags:
|
||||
|
||||
go test -v --bench . --benchmem
|
||||
|
||||
Keep in mind that each reviewer will run benchmarks on a different machine, with
|
||||
different specs, so the results from these benchmark tests may vary.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit vehicle_purchase.go` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [Go track's documentation](https://exercism.org/docs/tracks/go)
|
||||
- The [Go track's programming category on the forum](https://forum.exercism.org/c/programming/go)
|
||||
- [Exercism's programming category on the forum](https://forum.exercism.org/c/programming/5)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [How to Write Go Code](https://golang.org/doc/code.html)
|
||||
- [Effective Go](https://golang.org/doc/effective_go.html)
|
||||
- [Go Resources](http://golang.org/help)
|
||||
- [StackOverflow](http://stackoverflow.com/questions/tagged/go)
|
23
vehicle-purchase/HINTS.md
Normal file
23
vehicle-purchase/HINTS.md
Normal file
|
@ -0,0 +1,23 @@
|
|||
# Hints
|
||||
|
||||
## 1. Determine if you will need a driver's license
|
||||
|
||||
- Use the [equals comparison operator][comparison-operators] to check whether your input equals a certain string.
|
||||
- Use one of the two [logical operators][logical-operators] you learned about in the boolean concept to combine the two requirements.
|
||||
- You do **not** need an if-statement to solve this task. You can return the boolean expression you build directly.
|
||||
|
||||
## 2. Choose between two potential vehicles to buy
|
||||
|
||||
- Use a [comparison operator][comparison-operators] to determine which option comes first in lexicographical order.
|
||||
- Then set the value of a helper variable depending of the outcome of that comparison with the help of an an [if-else statement][if-statement].
|
||||
- Finally construct the recommendation sentence. For that you can use the `+` operator to concatenate the two strings.
|
||||
|
||||
## 3. Calculate an estimation for the price of a used vehicle
|
||||
|
||||
- Start with determining the percentage of the original price based on the age of the vehicle. Save it in a helper variable. Use an [if-else if-else statement][if-statement] as mentioned in the instructions.
|
||||
- In the two if conditions use [comparison operators][comparison-operators] to compare the age of the car to the threshold values.
|
||||
- To calculate the result, apply the percentage to the original price. For example `30% of x` can be calculated by dividing `30` by `100` and multiplying with `x`.
|
||||
|
||||
[comparison-operators]: https://golang.org/ref/spec#Comparison_operators
|
||||
[logical-operators]: https://golang.org/ref/spec#Logical_operators
|
||||
[if-statement]: https://golang.org/ref/spec#If_statements
|
152
vehicle-purchase/README.md
Normal file
152
vehicle-purchase/README.md
Normal file
|
@ -0,0 +1,152 @@
|
|||
# Vehicle Purchase
|
||||
|
||||
Welcome to Vehicle Purchase on Exercism's Go Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||||
|
||||
## Introduction
|
||||
|
||||
## Comparison
|
||||
|
||||
In Go numbers can be compared using the following relational and equality operators.
|
||||
|
||||
| Comparison | Operator |
|
||||
| ------------------| --------- |
|
||||
| equal | `==` |
|
||||
| not equal | `!=` |
|
||||
| less | `<` |
|
||||
| less or equal | `<=` |
|
||||
| greater | `>` |
|
||||
| greater or equal | `>=` |
|
||||
|
||||
The result of the comparison is always a boolean value, so either `true` or `false`.
|
||||
|
||||
```go
|
||||
a := 3
|
||||
|
||||
a != 4 // true
|
||||
a > 5 // false
|
||||
```
|
||||
|
||||
The comparison operators above can also be used to compare strings.
|
||||
In that case a lexicographical (dictionary) order is applied.
|
||||
For example:
|
||||
|
||||
```Go
|
||||
"apple" < "banana" // true
|
||||
"apple" > "banana" // false
|
||||
```
|
||||
|
||||
## If Statements
|
||||
|
||||
Conditionals in Go are similar to conditionals in other languages.
|
||||
The underlying type of any conditional operation is the `bool` type, which can have the value of `true` or `false`.
|
||||
Conditionals are often used as flow control mechanisms to check for various conditions.
|
||||
|
||||
For checking a particular case an `if` statement can be used, which executes its code if the underlying condition is `true` like this:
|
||||
|
||||
```go
|
||||
var value string
|
||||
|
||||
if value == "val" {
|
||||
return "was val"
|
||||
}
|
||||
```
|
||||
|
||||
In scenarios involving more than one case many `if` statements can be chained together using the `else if` and `else` statements.
|
||||
|
||||
```go
|
||||
var number int
|
||||
result := "This number is "
|
||||
|
||||
if number > 0 {
|
||||
result += "positive"
|
||||
} else if number < 0 {
|
||||
result += "negative"
|
||||
} else {
|
||||
result += "zero"
|
||||
}
|
||||
```
|
||||
|
||||
If statements can also include a short initialization statement that can be used to initialize one or more variables for the if statement.
|
||||
For example:
|
||||
|
||||
```go
|
||||
num := 7
|
||||
if v := 2 * num; v > 10 {
|
||||
fmt.Println(v)
|
||||
} else {
|
||||
fmt.Println(num)
|
||||
}
|
||||
// Output: 14
|
||||
```
|
||||
|
||||
> Note: any variables created in the initialization statement go out of scope after the end of the if statement.
|
||||
|
||||
## Instructions
|
||||
|
||||
In this exercise, you are going to write some code to help you prepare to buy a vehicle.
|
||||
|
||||
You have three tasks, one to determine if you need a license, one to help you choose between two vehicles and one to estimate the acceptable price for a used vehicle.
|
||||
|
||||
## 1. Determine if you will need a driver's license
|
||||
|
||||
Some vehicle kinds require a driver's license to operate them.
|
||||
Assume only the kinds `"car"` and `"truck"` require a license, everything else can be operated without a license.
|
||||
|
||||
Implement the `NeedsLicense(kind)` function that takes the kind of vehicle and returns a boolean indicating whether you need a license for that kind of vehicle.
|
||||
|
||||
```go
|
||||
needLicense := NeedsLicense("car")
|
||||
// => true
|
||||
|
||||
needLicense = NeedsLicense("bike")
|
||||
// => false
|
||||
|
||||
needLicense = NeedsLicense("truck")
|
||||
// => true
|
||||
```
|
||||
|
||||
## 2. Choose between two potential vehicles to buy
|
||||
|
||||
You evaluate your options of available vehicles.
|
||||
You manage to narrow it down to two options but you need help making the final decision.
|
||||
For that, implement the function `ChooseVehicle(option1, option2)` that takes two vehicles as arguments and returns a decision that includes the option that comes first in lexicographical order.
|
||||
|
||||
```go
|
||||
vehicle := ChooseVehicle("Wuling Hongguang", "Toyota Corolla")
|
||||
// => "Toyota Corolla is clearly the better choice."
|
||||
|
||||
ChooseVehicle("Volkswagen Beetle", "Volkswagen Golf")
|
||||
// => "Volkswagen Beetle is clearly the better choice."
|
||||
```
|
||||
|
||||
## 3. Calculate an estimation for the price of a used vehicle
|
||||
|
||||
Now that you made a decision, you want to make sure you get a fair price at the dealership.
|
||||
Since you are interested in buying a used vehicle, the price depends on how old the vehicle is.
|
||||
For a rough estimate, assume if the vehicle is less than 3 years old, it costs 80% of the original price it had when it was brand new.
|
||||
If it is at least 10 years old, it costs 50%.
|
||||
If the vehicle is at least 3 years old but less than 10 years, it costs 70% of the original price.
|
||||
|
||||
Implement the `CalculateResellPrice(originalPrice, age)` function that applies this logic using `if`, `else if` and `else` (there are other ways if you want to practice).
|
||||
It takes the original price and the age of the vehicle as arguments and returns the estimated price in the dealership.
|
||||
|
||||
```go
|
||||
CalculateResellPrice(1000, 1)
|
||||
// => 800
|
||||
|
||||
CalculateResellPrice(1000, 5)
|
||||
// => 700
|
||||
|
||||
CalculateResellPrice(1000, 15)
|
||||
// => 500
|
||||
```
|
||||
|
||||
**Note** the return value is a `float64`.
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @kahgoh
|
3
vehicle-purchase/go.mod
Normal file
3
vehicle-purchase/go.mod
Normal file
|
@ -0,0 +1,3 @@
|
|||
module purchase
|
||||
|
||||
go 1.18
|
16
vehicle-purchase/vehicle_purchase.go
Normal file
16
vehicle-purchase/vehicle_purchase.go
Normal file
|
@ -0,0 +1,16 @@
|
|||
package purchase
|
||||
|
||||
// NeedsLicense determines whether a license is needed to drive a type of vehicle. Only "car" and "truck" require a license.
|
||||
func NeedsLicense(kind string) bool {
|
||||
panic("NeedsLicense not implemented")
|
||||
}
|
||||
|
||||
// ChooseVehicle recommends a vehicle for selection. It always recommends the vehicle that comes first in lexicographical order.
|
||||
func ChooseVehicle(option1, option2 string) string {
|
||||
panic("ChooseVehicle not implemented")
|
||||
}
|
||||
|
||||
// CalculateResellPrice calculates how much a vehicle can resell for at a certain age.
|
||||
func CalculateResellPrice(originalPrice, age float64) float64 {
|
||||
panic("CalculateResellPrice not implemented")
|
||||
}
|
188
vehicle-purchase/vehicle_purchase_test.go
Normal file
188
vehicle-purchase/vehicle_purchase_test.go
Normal file
|
@ -0,0 +1,188 @@
|
|||
package purchase
|
||||
|
||||
import (
|
||||
"math"
|
||||
"testing"
|
||||
)
|
||||
|
||||
const floatEqualityThreshold = 1e-5
|
||||
|
||||
func TestNeedsLicense(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
kind string
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
name: "need a license for a car",
|
||||
kind: "car",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "need a license for a truck",
|
||||
kind: "truck",
|
||||
expected: true,
|
||||
},
|
||||
{
|
||||
name: "does not need a license for a bike",
|
||||
kind: "bike",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "does not need a license for a stroller",
|
||||
kind: "stroller",
|
||||
expected: false,
|
||||
},
|
||||
{
|
||||
name: "does not need a license for a e-scooter",
|
||||
kind: "e-scooter",
|
||||
expected: false,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := NeedsLicense(test.kind)
|
||||
if actual != test.expected {
|
||||
t.Errorf(
|
||||
"NeedsLicense(%q) = %t, want %t",
|
||||
test.kind,
|
||||
actual,
|
||||
test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestChooseVehicle(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
choice1 string
|
||||
choice2 string
|
||||
expected string
|
||||
}{
|
||||
{
|
||||
name: "chooses Bugatti over Ford",
|
||||
choice1: "Bugatti Veyron",
|
||||
choice2: "Ford Pinto",
|
||||
expected: "Bugatti Veyron is clearly the better choice.",
|
||||
}, {
|
||||
name: "chooses Chery over Kia",
|
||||
choice1: "Chery EQ",
|
||||
choice2: "Kia Niro Elektro",
|
||||
expected: "Chery EQ is clearly the better choice.",
|
||||
}, {
|
||||
name: "chooses Ford Focus over Ford Pinto",
|
||||
choice1: "Ford Focus",
|
||||
choice2: "Ford Pinto",
|
||||
expected: "Ford Focus is clearly the better choice.",
|
||||
}, {
|
||||
name: "chooses 2018 over 2020",
|
||||
choice1: "2018 Bergamont City",
|
||||
choice2: "2020 Gazelle Medeo",
|
||||
expected: "2018 Bergamont City is clearly the better choice.",
|
||||
}, {
|
||||
name: "chooses Bugatti over ford",
|
||||
choice1: "Bugatti Veyron",
|
||||
choice2: "ford",
|
||||
expected: "Bugatti Veyron is clearly the better choice.",
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := ChooseVehicle(test.choice1, test.choice2)
|
||||
if actual != test.expected {
|
||||
t.Errorf(
|
||||
"ChooseVehicle(%q, %q) = %q, want %q",
|
||||
test.choice1,
|
||||
test.choice2,
|
||||
actual,
|
||||
test.expected)
|
||||
}
|
||||
|
||||
// The result should be independent of the order in which the choices are given.
|
||||
actual = ChooseVehicle(test.choice2, test.choice1)
|
||||
if actual != test.expected {
|
||||
t.Errorf(
|
||||
"ChooseVehicle(%q, %q) = %q, want %q",
|
||||
test.choice2,
|
||||
test.choice1,
|
||||
actual,
|
||||
test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestCalculateResellPrice(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
originalPrice float64
|
||||
age float64
|
||||
expected float64
|
||||
}{
|
||||
{
|
||||
name: "price is reduced to 80% for age below 3",
|
||||
originalPrice: 40000,
|
||||
age: 2,
|
||||
expected: 32000,
|
||||
},
|
||||
{
|
||||
name: "price is reduced to 80% for age below 3",
|
||||
originalPrice: 40000,
|
||||
age: 2.5,
|
||||
expected: 32000,
|
||||
},
|
||||
{
|
||||
name: "price is reduced to 70% for age 3",
|
||||
originalPrice: 40000,
|
||||
age: 3,
|
||||
expected: 28000,
|
||||
},
|
||||
{
|
||||
name: "price is reduced to 70% for age 7",
|
||||
originalPrice: 40000,
|
||||
age: 7,
|
||||
expected: 28000,
|
||||
},
|
||||
{
|
||||
name: "price is reduced to 50% for age 10",
|
||||
originalPrice: 25000,
|
||||
age: 10,
|
||||
expected: 12500,
|
||||
},
|
||||
{
|
||||
name: "price is reduced to 50% for age 11",
|
||||
originalPrice: 50000,
|
||||
age: 11,
|
||||
expected: 25000,
|
||||
},
|
||||
{
|
||||
name: "float price is reduced to 70% for age 8,",
|
||||
originalPrice: 39000.000001,
|
||||
age: 8,
|
||||
expected: 27300.0000007,
|
||||
},
|
||||
}
|
||||
|
||||
for _, test := range tests {
|
||||
t.Run(test.name, func(t *testing.T) {
|
||||
actual := CalculateResellPrice(test.originalPrice, test.age)
|
||||
if !floatingPointEquals(actual, test.expected) {
|
||||
t.Errorf(
|
||||
"CalculateResellPrice(%v, %v) = %v, want %v",
|
||||
test.originalPrice,
|
||||
test.age,
|
||||
actual,
|
||||
test.expected)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func floatingPointEquals(got, want float64) bool {
|
||||
absoluteDifferenceBelowThreshold := math.Abs(got-want) <= floatEqualityThreshold
|
||||
relativeDifferenceBelowThreshold := math.Abs(got-want)/(math.Abs(got)+math.Abs(want)) <= floatEqualityThreshold
|
||||
return absoluteDifferenceBelowThreshold || relativeDifferenceBelowThreshold
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue