Add new exercises

This commit is contained in:
Blizzard Finnegan 2025-03-09 14:22:56 -04:00
parent 83565e8467
commit 22093ac00b
Signed by: blizzardfinnegan
GPG key ID: 61C1E13067E0018E
31 changed files with 1528 additions and 0 deletions

View 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"
}

View 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
View 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
View 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
View file

@ -0,0 +1,3 @@
module school
go 1.16

View 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")
}

View 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
}
}

View 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
}
}

View 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
View 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
View 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
View 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
View file

@ -0,0 +1,3 @@
module partyrobot
go 1.18

View 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")
}

View 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)
}
}
})
}
}

View 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"
}

View 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}

View 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)

View 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

View 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,
},
}

View file

@ -0,0 +1,3 @@
module variablelengthquantity
go 1.16

View 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")
}

View 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)
}
}

View 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
}
}

View 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
View 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
View 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
View 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
View file

@ -0,0 +1,3 @@
module purchase
go 1.18

View 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")
}

View 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
}