From 58bff89e83f03e4d55ff523248dff3438ebf24e4 Mon Sep 17 00:00:00 2001 From: Tomas Doran Date: Sun, 19 Sep 2021 18:02:57 +0100 Subject: [PATCH 1/4] Remove unnecessary content from chessboard introduction. This is alredy covered in concepts/range-iteration/introduction.md and so, as it's not needed for the exercise it shouldn't be in the exercise. Fixes #1604 --- exercises/concept/chessboard/.docs/introduction.md | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/exercises/concept/chessboard/.docs/introduction.md b/exercises/concept/chessboard/.docs/introduction.md index 99bc47259..5c69fec71 100644 --- a/exercises/concept/chessboard/.docs/introduction.md +++ b/exercises/concept/chessboard/.docs/introduction.md @@ -78,20 +78,6 @@ for i := range xi { // 2 ``` -Last but not least, if you are required to perform some action but you are not -interested in values nor keys of the slice or map, you can omit both index and -value: - -```go -xi := []int{10, 20, 30} -count := 0 -for range xi { - count++ -} -// count value: -// 3 -``` - ## Non-struct types You've previously seen defining struct types, but it's also possible to define non-struct types which you can use as an alias for a built in type declaration, and you can define reciever functions on them to extend them in the same way as struct types. From f204b3f5b1457197b4117337cd307daa1a4e5878 Mon Sep 17 00:00:00 2001 From: Tomas Doran Date: Sun, 19 Sep 2021 18:08:27 +0100 Subject: [PATCH 2/4] Replace byte with int in chessboard exercise. Fixes #1601 --- .../concept/chessboard/.docs/instructions.md | 6 +- .../concept/chessboard/.meta/exemplar.go | 6 +- exercises/concept/chessboard/chessboard.go | 6 +- .../concept/chessboard/chessboard_test.go | 58 +++++++++---------- 4 files changed, 38 insertions(+), 38 deletions(-) diff --git a/exercises/concept/chessboard/.docs/instructions.md b/exercises/concept/chessboard/.docs/instructions.md index 2d58ebd3e..f18c9d38d 100644 --- a/exercises/concept/chessboard/.docs/instructions.md +++ b/exercises/concept/chessboard/.docs/instructions.md @@ -2,15 +2,15 @@ As a chess enthusiast, you would like to write your own version of the game. Yes, there maybe plenty of implementations of chess available online already, but yours will be unique! -Each square of the chessboard is identified by a letter-number pair. The vertical columns of squares, called files, are labeled A through H. The horizontal rows of squares, called ranks, are numbered 1 to 8. +Each square of the chessboard is identified by a letter-number pair. The vertical columns of squares, called files, are numbered 1 through 8. The horizontal rows of squares, called ranks, are numbered 1 to 8. ## 1. Given a Chessboard and a Rank, count how many squares are occupied -Decorate the `Chessboard` type with the `CountInRank(rank byte) int` function. +Decorate the `Chessboard` type with the `CountInRank(rank int) int` function. It should count occupied squares ranging over a map. Return an integer. ```go -CountInRank('A') +CountInRank(1) // => 6 ``` diff --git a/exercises/concept/chessboard/.meta/exemplar.go b/exercises/concept/chessboard/.meta/exemplar.go index 9a0103b69..a0b985c05 100644 --- a/exercises/concept/chessboard/.meta/exemplar.go +++ b/exercises/concept/chessboard/.meta/exemplar.go @@ -3,12 +3,12 @@ package chessboard // Rank stores if a square is occupied by a piece type Rank []bool -// Chessboard contains eight Ranks, accessed with values from 'A' to 'H' -type Chessboard map[byte]Rank +// Chessboard contains eight Ranks, accessed with values from '0' to '7' +type Chessboard map[int]Rank // CountInRank returns how many squares are occupied in the chessboard, // within the given rank -func (cb Chessboard) CountInRank(rank byte) (ret int) { +func (cb Chessboard) CountInRank(rank int) (ret int) { for _, r := range cb[rank] { if r { ret++ diff --git a/exercises/concept/chessboard/chessboard.go b/exercises/concept/chessboard/chessboard.go index b9b4c4c95..5a3303ec4 100644 --- a/exercises/concept/chessboard/chessboard.go +++ b/exercises/concept/chessboard/chessboard.go @@ -3,12 +3,12 @@ package chessboard // Rank stores if a square is occupied by a piece type Rank []bool -// Chessboard contains eight Ranks, accessed with values from 'A' to 'H' -type Chessboard map[byte]Rank +// Chessboard contains eight Ranks, accessed with values from '0' to '7' +type Chessboard map[int]Rank // CountInRank returns how many squares are occupied in the chessboard, // within the given rank -func (cb Chessboard) CountInRank(rank byte) (ret int) { +func (cb Chessboard) CountInRank(rank int) (ret int) { panic("Please implement CountInRank()") } diff --git a/exercises/concept/chessboard/chessboard_test.go b/exercises/concept/chessboard/chessboard_test.go index 7c436b88f..96ef9aee8 100644 --- a/exercises/concept/chessboard/chessboard_test.go +++ b/exercises/concept/chessboard/chessboard_test.go @@ -7,48 +7,48 @@ import ( // newChessboard return a *Chessboard for tests // // 1 2 3 4 5 6 7 8 -// A # _ # _ _ _ _ # A -// B _ _ _ _ # _ _ _ B -// C _ _ # _ _ _ _ _ C -// D _ _ _ _ _ _ _ _ D -// E _ _ _ _ _ # _ # E -// F _ _ _ _ _ _ _ _ F -// G _ _ _ # _ _ _ _ G -// H # # # # # # _ # H +// 1 # _ # _ _ _ _ # 1 +// 2 _ _ _ _ # _ _ _ 2 +// 3 _ _ # _ _ _ _ _ 3 +// 4 _ _ _ _ _ _ _ _ 4 +// 5 _ _ _ _ _ # _ # 5 +// 6 _ _ _ _ _ _ _ _ 6 +// 7 _ _ _ # _ _ _ _ 7 +// 8 # # # # # # _ # 8 // 1 2 3 4 5 6 7 8 func newChessboard() *Chessboard { return &Chessboard{ - 'A': Rank{true, false, true, false, false, false, false, true}, - 'B': Rank{false, false, false, false, true, false, false, false}, - 'C': Rank{false, false, true, false, false, false, false, false}, - 'D': Rank{false, false, false, false, false, false, false, false}, - 'E': Rank{false, false, false, false, false, true, false, true}, - 'F': Rank{false, false, false, false, false, false, false, false}, - 'G': Rank{false, false, false, true, false, false, false, false}, - 'H': Rank{true, true, true, true, true, true, false, true}, + 1: Rank{true, false, true, false, false, false, false, true}, + 2: Rank{false, false, false, false, true, false, false, false}, + 3: Rank{false, false, true, false, false, false, false, false}, + 4: Rank{false, false, false, false, false, false, false, false}, + 5: Rank{false, false, false, false, false, true, false, true}, + 6: Rank{false, false, false, false, false, false, false, false}, + 7: Rank{false, false, false, true, false, false, false, false}, + 8: Rank{true, true, true, true, true, true, false, true}, } } func TestCountInRank(t *testing.T) { cb := newChessboard() for _, test := range []struct { - in byte + in int out int }{ - {'A', 3}, - {'B', 1}, - {'C', 1}, - {'D', 0}, - {'E', 2}, - {'F', 0}, - {'G', 1}, - {'H', 7}, - {'Z', 0}, + {1, 3}, + {2, 1}, + {3, 1}, + {4, 0}, + {5, 2}, + {6, 0}, + {7, 1}, + {8, 7}, + {9, 0}, } { if out := cb.CountInRank(test.in); out != test.out { t.Errorf( - "CountInRank('%v') returned %v while %v was expected\n", - string(test.in), + "CountInRank(%v) returned %v while %v was expected\n", + test.in, out, test.out, ) @@ -74,7 +74,7 @@ func TestCountInFile(t *testing.T) { } { if out := cb.CountInFile(test.in); out != test.out { t.Errorf( - "CountInFile('%v') returned %v while %v was expected\n", + "CountInFile(%v) returned %v while %v was expected\n", test.in, out, test.out, From 8f3668c8a65c21d982f2d0c70c67cf40025b41ea Mon Sep 17 00:00:00 2001 From: Tomas Doran Date: Sun, 19 Sep 2021 18:19:17 +0100 Subject: [PATCH 3/4] Make chessboard no longer depend on methods concept --- config.json | 3 +-- .../concept/chessboard/.meta/exemplar.go | 10 +++++----- exercises/concept/chessboard/chessboard.go | 8 ++++---- .../concept/chessboard/chessboard_test.go | 20 +++++++++---------- 4 files changed, 20 insertions(+), 21 deletions(-) diff --git a/config.json b/config.json index ffb33a382..3c1a34a51 100644 --- a/config.json +++ b/config.json @@ -224,8 +224,7 @@ "prerequisites": [ "conditionals-if", "maps", - "slices", - "methods" + "slices" ], "status": "beta" }, diff --git a/exercises/concept/chessboard/.meta/exemplar.go b/exercises/concept/chessboard/.meta/exemplar.go index a0b985c05..c9e8bd567 100644 --- a/exercises/concept/chessboard/.meta/exemplar.go +++ b/exercises/concept/chessboard/.meta/exemplar.go @@ -8,7 +8,7 @@ type Chessboard map[int]Rank // CountInRank returns how many squares are occupied in the chessboard, // within the given rank -func (cb Chessboard) CountInRank(rank int) (ret int) { +func CountInRank(cb Chessboard, rank int) (ret int) { for _, r := range cb[rank] { if r { ret++ @@ -19,7 +19,7 @@ func (cb Chessboard) CountInRank(rank int) (ret int) { // CountInFile returns how many squares are occupied in the chessboard, // within the given file -func (cb Chessboard) CountInFile(file int) (ret int) { +func CountInFile(cb Chessboard, file int) (ret int) { if file < 1 || file > 8 { return } @@ -32,7 +32,7 @@ func (cb Chessboard) CountInFile(file int) (ret int) { } // CountAll should count how many squares are present in the chessboard -func (cb Chessboard) CountAll() (ret int) { +func CountAll(cb Chessboard) (ret int) { for _, rank := range cb { for range rank { ret++ @@ -42,9 +42,9 @@ func (cb Chessboard) CountAll() (ret int) { } // CountOccupied returns how many squares are occupied in the chessboard -func (cb Chessboard) CountOccupied() (ret int) { +func CountOccupied(cb Chessboard) (ret int) { for rank := range cb { - ret += cb.CountInRank(rank) + ret += CountInRank(cb, rank) } return ret } diff --git a/exercises/concept/chessboard/chessboard.go b/exercises/concept/chessboard/chessboard.go index 5a3303ec4..8a97122b8 100644 --- a/exercises/concept/chessboard/chessboard.go +++ b/exercises/concept/chessboard/chessboard.go @@ -8,22 +8,22 @@ type Chessboard map[int]Rank // CountInRank returns how many squares are occupied in the chessboard, // within the given rank -func (cb Chessboard) CountInRank(rank int) (ret int) { +func CountInRank(cb Chessboard, rank int) (ret int) { panic("Please implement CountInRank()") } // CountInFile returns how many squares are occupied in the chessboard, // within the given file -func (cb Chessboard) CountInFile(file int) (ret int) { +func CountInFile(cb Chessboard, file int) (ret int) { panic("Please implement CountInFile()") } // CountAll should count how many squares are present in the chessboard -func (cb Chessboard) CountAll() (ret int) { +func CountAll(cb Chessboard) (ret int) { panic("Please implement CountAll()") } // CountOccupied returns how many squares are occupied in the chessboard -func (cb Chessboard) CountOccupied() (ret int) { +func CountOccupied(cb Chessboard) (ret int) { panic("Please implement CountOccupied()") } diff --git a/exercises/concept/chessboard/chessboard_test.go b/exercises/concept/chessboard/chessboard_test.go index 96ef9aee8..84bccc55a 100644 --- a/exercises/concept/chessboard/chessboard_test.go +++ b/exercises/concept/chessboard/chessboard_test.go @@ -16,8 +16,8 @@ import ( // 7 _ _ _ # _ _ _ _ 7 // 8 # # # # # # _ # 8 // 1 2 3 4 5 6 7 8 -func newChessboard() *Chessboard { - return &Chessboard{ +func newChessboard() Chessboard { + return Chessboard{ 1: Rank{true, false, true, false, false, false, false, true}, 2: Rank{false, false, false, false, true, false, false, false}, 3: Rank{false, false, true, false, false, false, false, false}, @@ -45,9 +45,9 @@ func TestCountInRank(t *testing.T) { {8, 7}, {9, 0}, } { - if out := cb.CountInRank(test.in); out != test.out { + if out := CountInRank(cb, test.in); out != test.out { t.Errorf( - "CountInRank(%v) returned %v while %v was expected\n", + "CountInRank(chessboard, %v) returned %v while %v was expected\n", test.in, out, test.out, @@ -72,9 +72,9 @@ func TestCountInFile(t *testing.T) { {8, 3}, {100, 0}, } { - if out := cb.CountInFile(test.in); out != test.out { + if out := CountInFile(cb, test.in); out != test.out { t.Errorf( - "CountInFile(%v) returned %v while %v was expected\n", + "CountInFile(chessboard, %v) returned %v while %v was expected\n", test.in, out, test.out, @@ -86,15 +86,15 @@ func TestCountInFile(t *testing.T) { func TestCountAll(t *testing.T) { cb := newChessboard() wanted := 64 - if out := cb.CountAll(); out != wanted { - t.Errorf("CountAll() returned %v while %v was expected", out, wanted) + if out := CountAll(cb); out != wanted { + t.Errorf("CountAll(chessboard) returned %v while %v was expected", out, wanted) } } func TestCountOccupied(t *testing.T) { cb := newChessboard() wanted := 15 - if out := cb.CountOccupied(); out != wanted { - t.Errorf("CountOccupied() returned %v while %v was expected", out, wanted) + if out := CountOccupied(cb); out != wanted { + t.Errorf("CountOccupied(chessboard) returned %v while %v was expected", out, wanted) } } From d5a5d71898c38be0ad601bb4c570e124d13b1723 Mon Sep 17 00:00:00 2001 From: Tomas Doran Date: Sun, 19 Sep 2021 18:44:58 +0100 Subject: [PATCH 4/4] Add type-definitions concept to explain non-struct type definitions. This is a first crack at implementing the `type-definition` concept as proposed @junedev Updates chessboard to teach that type, and to remove mention of methods as these will come afterwards. This fixes #1602. Fixes #1603 by making it obsolete --- concepts/type-definitions/.meta/config.json | 5 ++ concepts/type-definitions/about.md | 46 +++++++++++++++++++ concepts/type-definitions/introduction.md | 46 +++++++++++++++++++ concepts/type-definitions/links.json | 18 ++++++++ config.json | 14 ++++-- .../concept/chessboard/.docs/introduction.md | 8 ++-- exercises/concept/chessboard/chessboard.go | 6 +-- 7 files changed, 132 insertions(+), 11 deletions(-) create mode 100644 concepts/type-definitions/.meta/config.json create mode 100644 concepts/type-definitions/about.md create mode 100644 concepts/type-definitions/introduction.md create mode 100644 concepts/type-definitions/links.json diff --git a/concepts/type-definitions/.meta/config.json b/concepts/type-definitions/.meta/config.json new file mode 100644 index 000000000..a6db7f10d --- /dev/null +++ b/concepts/type-definitions/.meta/config.json @@ -0,0 +1,5 @@ +{ + "blurb": "Go allows you to define custom types.", + "authors": ["bobtfish"], + "contributors": [] +} diff --git a/concepts/type-definitions/about.md b/concepts/type-definitions/about.md new file mode 100644 index 000000000..ecec2f654 --- /dev/null +++ b/concepts/type-definitions/about.md @@ -0,0 +1,46 @@ +# About + +## Struct types + +We've already seen struct types; to recap a `struct` is a sequence of named elements called _fields_, each field having a name and type. +The name of a field must be unique within the struct. +`Structs` can be compared with the _class_ in the Object Oriented Programming paradigm. + +You create a new struct by using the `type` and `struct` keywords, then explicitly define the name and type of the fields as shown in the example below. + +```go +type StructName struct{ + field1 fieldType1 + field2 fieldType2 +} +``` + +## Non-struct types + +It's also possible to define non-struct types which you can use as an alias for a built in type declarations. + +```go +type Name string +func SayHello(n Name) { + fmt.Printf("Hello %s\n", n) +} +n := Name("Fred") +SayHello(n) +// Output: Hello Fred +``` + +You can also define non-struct types composed of arrays and maps. + +```go +type Names []string +func SayHello(n Names) { + for _, name := range n { + fmt.Printf("Hello %s\n", name) + } +} +n := Names([]string{"Fred", "Bill"}) +SayHello(n) +// Output: +// Hello Fred +// Hello Bill +``` diff --git a/concepts/type-definitions/introduction.md b/concepts/type-definitions/introduction.md new file mode 100644 index 000000000..6cae9065e --- /dev/null +++ b/concepts/type-definitions/introduction.md @@ -0,0 +1,46 @@ +# Introduction + +## Struct types + +We've already seen struct types; to recap a `struct` is a sequence of named elements called _fields_, each field having a name and type. +The name of a field must be unique within the struct. +`Structs` can be compared with the _class_ in the Object Oriented Programming paradigm. + +You create a new struct by using the `type` and `struct` keywords, then explicitly define the name and type of the fields as shown in the example below. + +```go +type StructName struct{ + field1 fieldType1 + field2 fieldType2 +} +``` + +## Non-struct types + +It's also possible to define non-struct types which you can use as an alias for a built in type declarations. + +```go +type Name string +func SayHello(n Name) { + fmt.Printf("Hello %s\n", n) +} +n := Name("Fred") +SayHello(n) +// Output: Hello Fred +``` + +You can also define non-struct types composed of arrays and maps. + +```go +type Names []string +func SayHello(n Names) { + for _, name := range n { + fmt.Printf("Hello %s\n", name) + } +} +n := Names([]string{"Fred", "Bill"}) +SayHello(n) +// Output: +// Hello Fred +// Hello Bill +``` diff --git a/concepts/type-definitions/links.json b/concepts/type-definitions/links.json new file mode 100644 index 000000000..8f5637ce5 --- /dev/null +++ b/concepts/type-definitions/links.json @@ -0,0 +1,18 @@ +[ + { + "url": "https://tour.golang.org/moretypes/2", + "description": "A Tour of Go" + }, + { + "url": "https://go101.org/article/type-system-overview.html", + "description": "Go Type System Overview" + }, + { + "url": "https://medium.com/rungo/structures-in-go-76377cc106a2", + "description": "Structures in Go" + }, + { + "url": "https://gobyexample.com/structs", + "description": "Go by Example: Structs" + } +] diff --git a/config.json b/config.json index 3c1a34a51..dd21ffa87 100644 --- a/config.json +++ b/config.json @@ -173,7 +173,8 @@ ], "prerequisites": [ "structs", - "string-formatting" + "string-formatting", + "type-definitions" ], "status": "beta" }, @@ -219,12 +220,14 @@ "slug": "chessboard", "uuid": "b5f1c789-adf6-487c-95b0-c6bce23d711b", "concepts": [ - "range-iteration" + "range-iteration", + "type-definitions" ], "prerequisites": [ "conditionals-if", "maps", - "slices" + "slices", + "structs" ], "status": "beta" }, @@ -1850,6 +1853,11 @@ "slug": "type-conversion", "uuid": "4f3d535e-cec8-4303-ac5a-ed91a53bd594" }, + { + "name": "Type Definitions", + "slug": "type-definitions", + "uuid": "ef4bfcfb-fa81-4d80-be63-a50c47653490" + }, { "name": "Zero Values", "slug": "zero-values", diff --git a/exercises/concept/chessboard/.docs/introduction.md b/exercises/concept/chessboard/.docs/introduction.md index 5c69fec71..2bffce76b 100644 --- a/exercises/concept/chessboard/.docs/introduction.md +++ b/exercises/concept/chessboard/.docs/introduction.md @@ -84,11 +84,11 @@ You've previously seen defining struct types, but it's also possible to define n ```go type Name string -func (n Name) SayHello() { +func SayHello(n Name) { fmt.Printf("Hello %s\n", n) } n := Name("Fred") -n.SayHello() +SayHello(n) // Output: Hello Fred ``` @@ -96,13 +96,13 @@ You can also define non-struct types composed of arrays and maps. ```go type Names []string -func (n Names) SayHello() { +func SayHello(n Names) { for _, name := range n { fmt.Printf("Hello %s\n", name) } } n := Names([]string{"Fred", "Bill"}) -n.SayHello() +SayHello(n) // Output: // Hello Fred // Hello Bill diff --git a/exercises/concept/chessboard/chessboard.go b/exercises/concept/chessboard/chessboard.go index 8a97122b8..7e181fe16 100644 --- a/exercises/concept/chessboard/chessboard.go +++ b/exercises/concept/chessboard/chessboard.go @@ -1,10 +1,8 @@ package chessboard -// Rank stores if a square is occupied by a piece -type Rank []bool +// Declare a type named Rank which stores if a square is occupied by a piece - this will be a slice of bools -// Chessboard contains eight Ranks, accessed with values from '0' to '7' -type Chessboard map[int]Rank +// Declare a type named Chessboard contains a map of eight Ranks, accessed with values from 1 to 8 // CountInRank returns how many squares are occupied in the chessboard, // within the given rank