Skip to content

Commit

Permalink
Start go/card-tricks
Browse files Browse the repository at this point in the history
  • Loading branch information
parkerbxyz committed Apr 27, 2024
1 parent ab7e4f3 commit 718293e
Show file tree
Hide file tree
Showing 6 changed files with 668 additions and 0 deletions.
41 changes: 41 additions & 0 deletions go/card-tricks/HELP.md
Original file line number Diff line number Diff line change
@@ -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 card_tricks.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)
44 changes: 44 additions & 0 deletions go/card-tricks/HINTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# Hints

## General

- Slices in Go are zero-based. The first index in a slice is `0`.
- The builtin [`append`][append-builtin] function is [`variadic`][variadic-gobyexample]
- You can append the elements of one slice to another slice by using the three dots notation:

```go
a := []int{1, 3}
b := []int{4, 2, 6}
c := append(a, b...)
fmt.Println(c)
// Output: [1 3 4 2 6]
```

## 1. Create a slice with certain cards

- To create a slice pre-filled with some data, use the slice literal notation:
`s := []T{x1, x2, ..., xn}`

## 2. Retrieve a card from a stack

- To get the `n`th item of a slice [use an index][go-slices].
- To check if an item exists in a slice use a conditional and compare the index with the [length of the slice][len-builtin].

## 3. Exchange a card in the stack

- To set the `n`th item in a slice [use an index][go-slices] and assign a new value to it.
- To add a new item to then end of a slice use the `append` function.

## 4. Add cards to the top of the stack

- Adding items to the front of a slice can be done by appending the elements of the original slice to the `value` argument slice.

## 5. Remove a card from the stack

- Removing an item from a slice can be done by appending the part after `index` to the part before index.

[go-slices]: https://blog.golang.org/go-slices-usage-and-internals
[make-builtin]: https://golang.org/pkg/builtin/#make
[len-builtin]: https://golang.org/pkg/builtin/#len
[append-builtin]: https://golang.org/pkg/builtin/#append
[variadic-gobyexample]: https://gobyexample.com/variadic-functions
253 changes: 253 additions & 0 deletions go/card-tricks/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,253 @@
# Card Tricks

Welcome to Card Tricks 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

## Slices

Slices in Go are similar to lists or arrays in other languages.
They hold several elements of a specific type (or interface).

Slices in Go are based on arrays.
Arrays have a fixed size.
A slice, on the other hand, is a dynamically-sized, flexible view of the elements of an array.

A slice is written like `[]T` with `T` being the type of the elements in the slice:

```go
var empty []int // an empty slice
withData := []int{0,1,2,3,4,5} // a slice pre-filled with some data
```

You can get or set an element at a given zero-based index using the square-bracket notation:

```go
withData[1] = 5
x := withData[1] // x is now 5
```

You can create a new slice from an existing slice by getting a range of elements.
Once again using square-bracket notation, but specifying both a starting (inclusive) and ending (exclusive) index.
If you don't specify a starting index, it defaults to 0.
If you don't specify an ending index, it defaults to the length of the slice.

```go
newSlice := withData[2:4]
// => []int{2,3}
newSlice := withData[:2]
// => []int{0,1}
newSlice := withData[2:]
// => []int{2,3,4,5}
newSlice := withData[:]
// => []int{0,1,2,3,4,5}
```

You can add elements to a slice using the `append` function.
Below we append `4` and `2` to the `a` slice.

```go
a := []int{1, 3}
a = append(a, 4, 2)
// => []int{1,3,4,2}
```

`append` always returns a new slice, and when we just want to append elements to an existing slice, it's common to reassign it back to the slice variable we pass as the first argument as we did above.

`append` can also be used to merge two slices:

```go
nextSlice := []int{100,101,102}
newSlice := append(withData, nextSlice...)
// => []int{0,1,2,3,4,5,100,101,102}
```

## Variadic Functions

Usually, functions in Go accept only a fixed number of arguments.
However, it is also possible to write variadic functions in Go.

A variadic function is a function that accepts a variable number of arguments.

If the type of the last parameter in a function definition is prefixed by ellipsis `...`, then the function can accept any number of arguments for that parameter.

```go
func find(a int, b ...int) {
// ...
}
```

In the above function, parameter `b` is variadic and we can pass 0 or more arguments to `b`.

```go
find(5, 6)
find(5, 6, 7)
find(5)
```

~~~~exercism/caution
The variadic parameter must be the last parameter of the function.
~~~~

The way variadic functions work is by converting the variable number of arguments to a slice of the type of the variadic parameter.

Here is an example of an implementation of a variadic function.

```go
func find(num int, nums ...int) {
fmt.Printf("type of nums is %T\n", nums)

for i, v := range nums {
if v == num {
fmt.Println(num, "found at index", i, "in", nums)
return
}
}

fmt.Println(num, "not found in ", nums)
}

func main() {
find(89, 90, 91, 95)
// =>
// type of nums is []int
// 89 not found in [90 91 95]

find(45, 56, 67, 45, 90, 109)
// =>
// type of nums is []int
// 45 found at index 2 in [56 67 45 90 109]

find(87)
// =>
// type of nums is []int
// 87 not found in []
}
```

In line `find(89, 90, 91, 95)` of the program above, the variable number of arguments to the find function are `90`, `91` and `95`.
The `find` function expects a variadic int parameter after `num`.
Hence these three arguments will be converted by the compiler to a slice of type `int` `[]int{90, 91, 95}` and then it will be passed to the find function as `nums`.

Sometimes you already have a slice and want to pass that to a variadic function.
This can be achieved by passing the slice followed by `...`.
That will tell the compiler to use the slice as is inside the variadic function.
The step described above where a slice is created will simply be omitted in this case.

```go
list := []int{1, 2, 3}
find(1, list...) // "find" defined as shown above
```

[append-yourbasic]: https://yourbasic.org/golang/append-explained/

## Instructions

As a magician-to-be, Elyse needs to practice some basics. She has a stack of cards that she wants to manipulate.

To make things a bit easier she only uses the cards 1 to 10.

## 1. Create a slice with certain cards

When practicing with her cards, Elyse likes to start with her favorite three cards of the deck: 2, 6 and 9.
Write a function `FavoriteCards` that returns a slice with those cards in that order.

```go
cards := FavoriteCards()
fmt.Println(cards)
// Output: [2 6 9]
```

## 2. Retrieve a card from a stack

Return the card at position `index` from the given stack.

```go
card := GetItem([]int{1, 2, 4, 1}, 2) // card == 4
```

If the index is out of bounds (ie. if it is negative or after the end of the stack), we want to return `-1`:

```go
card := GetItem([]int{1, 2, 4, 1}, 10) // card == -1
```
~~~~exercism/note
By convention in Go, an error is returned instead of returning an "out-of-band" value.
Here the "out-of-band" value is `-1` when a positive integer is expected.
When returning an error, it's considered idiomatic to return the [`zero value`](https://www.geeksforgeeks.org/zero-value-in-golang/) with the error.
Returning an error with the proper return value will be covered in a future exercise.
~~~~

## 3. Exchange a card in the stack

Exchange the card at position `index` with the new card provided and return the adjusted stack.
Note that this will modify the input slice which is the expected behavior.

```go
index := 2
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 6 1]
```

If the index is out of bounds (ie. if it is negative or after the end of the stack), we want to append the new card to the end of the stack:

```go
index := -1
newCard := 6
cards := SetItem([]int{1, 2, 4, 1}, index, newCard)
fmt.Println(cards)
// Output: [1 2 4 1 6]
```

## 4. Add cards to the top of the stack

Add the card(s) specified in the `value` parameter at the top of the stack.

```go
slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice, 5, 1)
fmt.Println(cards)
// Output: [5 1 3 2 6 4 8]
```

If no argument is given for the `value` parameter, then the result equals the original slice.

```go
slice := []int{3, 2, 6, 4, 8}
cards := PrependItems(slice)
fmt.Println(cards)
// Output: [3 2 6 4 8]
```

## 5. Remove a card from the stack

Remove the card at position `index` from the stack and return the stack.
Note that this may modify the input slice which is ok.

```go
cards := RemoveItem([]int{3, 2, 6, 4, 8}, 2)
fmt.Println(cards)
// Output: [3 2 4 8]
```

If the index is out of bounds (ie. if it is negative or after the end of the stack), we want to leave the stack unchanged:

```go
cards := RemoveItem([]int{3, 2, 6, 4, 8}, 11)
fmt.Println(cards)
// Output: [3 2 6 4 8]
```

## Source

### Created by

- @tehsphinx

### Contributed to by

- @norbs57
28 changes: 28 additions & 0 deletions go/card-tricks/card_tricks.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
package cards

// FavoriteCards returns a slice with the cards 2, 6 and 9 in that order.
func FavoriteCards() []int {
panic("Please implement the FavoriteCards function")
}

// GetItem retrieves an item from a slice at given position.
// If the index is out of range, we want it to return -1.
func GetItem(slice []int, index int) int {
panic("Please implement the GetItem function")
}

// SetItem writes an item to a slice at given position overwriting an existing value.
// If the index is out of range the value needs to be appended.
func SetItem(slice []int, index, value int) []int {
panic("Please implement the SetItem function")
}

// PrependItems adds an arbitrary number of values at the front of a slice.
func PrependItems(slice []int, values ...int) []int {
panic("Please implement the PrependItems function")
}

// RemoveItem removes an item from a slice by modifying the existing slice.
func RemoveItem(slice []int, index int) []int {
panic("Please implement the RemoveItem function")
}
Loading

0 comments on commit 718293e

Please sign in to comment.