From 0aab0d17e90a3774274f2b3fe64a38e59ec0ee72 Mon Sep 17 00:00:00 2001 From: Inanc Gumus Date: Mon, 28 Jan 2019 14:23:59 +0300 Subject: [PATCH] add: append lecture examples --- 15-slices/05-append/1-theory/main.go | 39 ++++ 15-slices/05-append/2-example/main.go | 33 ++++ .../files/empty1.txt | 0 .../files/empty2.txt | 0 .../files/empty3.txt | 0 .../files/nonEmpty1.txt | 1 + .../files/nonEmpty2.txt | 1 + .../files/nonEmpty3.txt | 1 + .../main.go | 35 ++++ .../files/empty1.txt | 0 .../files/empty2.txt | 0 .../files/empty3.txt | 0 .../files/nonEmpty1.txt | 1 + .../files/nonEmpty2.txt | 1 + .../files/nonEmpty3.txt | 1 + .../main.go | 50 ++++++ .../07-slice-expressions/1-theory/main.go | 38 ++++ .../07-slice-expressions/2-example/main.go | 59 +++++++ .../08-slice-expressions-pagination/main.go | 58 ++++++ .../1-theory/main.go | 44 +++++ .../2-example/main.go | 50 ++++++ .../1-theory/main.go | 21 +++ .../2-example/main.go | 61 +++++++ .../1-theory/main.go | 31 ++++ .../2-example/main.go | 56 ++++++ .../1-theory/main.go | 22 +++ .../2-example/main.go | 54 ++++++ .../3-example-growth/main.go | 34 ++++ .../4-example-growth/main.go | 27 +++ .../13-png-parser/1-png-anatomy-format.md | 17 ++ .../13-png-parser/2-png-anatomy-example.md | 26 +++ .../images/broken-missing-ihdr.png | 5 + .../images/broken-missing-png-header.png | Bin 0 -> 164 bytes x-tba/slices/13-png-parser/images/gopher.png | Bin 0 -> 67555 bytes x-tba/slices/13-png-parser/main.go | 86 +++++++++ .../1-theory/main.go | 28 +++ .../2-example/main.go | 35 ++++ x-tba/slices/15-make/1-theory/main.go | 25 +++ x-tba/slices/15-make/2-example/main.go | 83 +++++++++ .../version-3-optimize/files/empty1.txt | 0 .../version-3-optimize/files/empty2.txt | 0 .../version-3-optimize/files/empty3.txt | 0 .../version-3-optimize/files/nonEmpty1.txt | 1 + .../version-3-optimize/files/nonEmpty2.txt | 1 + .../version-3-optimize/files/nonEmpty3.txt | 1 + .../version-3-optimize/main.go | 70 ++++++++ x-tba/slices/17-copy/01-usage/main.go | 28 +++ .../slices/17-copy/02-hacker-incident/main.go | 56 ++++++ .../version-1/main.go | 33 ++++ .../version-2/main.go | 30 ++++ .../version-3/main.go | 52 ++++++ .../01-solution-draw-the-board/main.go | 47 +++++ .../02-solution-drawing-loop/main.go | 68 +++++++ .../03-solution-final/main.go | 94 ++++++++++ .../04-solution-final-optimize/main.go | 92 ++++++++++ .../19-bouncing-ball-challenge/README.md | 166 ++++++++++++++++++ 56 files changed, 1762 insertions(+) create mode 100644 15-slices/05-append/1-theory/main.go create mode 100644 15-slices/05-append/2-example/main.go create mode 100644 15-slices/06-empty-file-finder-project-reading-empty-files/files/empty1.txt create mode 100644 15-slices/06-empty-file-finder-project-reading-empty-files/files/empty2.txt create mode 100644 15-slices/06-empty-file-finder-project-reading-empty-files/files/empty3.txt create mode 100644 15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty1.txt create mode 100644 15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty2.txt create mode 100644 15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty3.txt create mode 100644 15-slices/06-empty-file-finder-project-reading-empty-files/main.go create mode 100644 15-slices/07-empty-file-finder-project-writing-to-a-file/files/empty1.txt create mode 100644 15-slices/07-empty-file-finder-project-writing-to-a-file/files/empty2.txt create mode 100644 15-slices/07-empty-file-finder-project-writing-to-a-file/files/empty3.txt create mode 100644 15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty1.txt create mode 100644 15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty2.txt create mode 100644 15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty3.txt create mode 100644 15-slices/07-empty-file-finder-project-writing-to-a-file/main.go create mode 100644 x-tba/slices/07-slice-expressions/1-theory/main.go create mode 100644 x-tba/slices/07-slice-expressions/2-example/main.go create mode 100644 x-tba/slices/08-slice-expressions-pagination/main.go create mode 100644 x-tba/slices/09-slice-internals-1-backing-array/1-theory/main.go create mode 100644 x-tba/slices/09-slice-internals-1-backing-array/2-example/main.go create mode 100644 x-tba/slices/10-slice-internals-2-slice-header/1-theory/main.go create mode 100644 x-tba/slices/10-slice-internals-2-slice-header/2-example/main.go create mode 100644 x-tba/slices/11-slice-internals-3-len-cap/1-theory/main.go create mode 100644 x-tba/slices/11-slice-internals-3-len-cap/2-example/main.go create mode 100644 x-tba/slices/12-slice-internals-4-append/1-theory/main.go create mode 100644 x-tba/slices/12-slice-internals-4-append/2-example/main.go create mode 100644 x-tba/slices/12-slice-internals-4-append/3-example-growth/main.go create mode 100644 x-tba/slices/12-slice-internals-4-append/4-example-growth/main.go create mode 100644 x-tba/slices/13-png-parser/1-png-anatomy-format.md create mode 100644 x-tba/slices/13-png-parser/2-png-anatomy-example.md create mode 100644 x-tba/slices/13-png-parser/images/broken-missing-ihdr.png create mode 100644 x-tba/slices/13-png-parser/images/broken-missing-png-header.png create mode 100644 x-tba/slices/13-png-parser/images/gopher.png create mode 100644 x-tba/slices/13-png-parser/main.go create mode 100644 x-tba/slices/14-full-slice-expressions/1-theory/main.go create mode 100644 x-tba/slices/14-full-slice-expressions/2-example/main.go create mode 100644 x-tba/slices/15-make/1-theory/main.go create mode 100644 x-tba/slices/15-make/2-example/main.go create mode 100644 x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/empty1.txt create mode 100644 x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/empty2.txt create mode 100644 x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/empty3.txt create mode 100644 x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty1.txt create mode 100644 x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty2.txt create mode 100644 x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty3.txt create mode 100644 x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/main.go create mode 100644 x-tba/slices/17-copy/01-usage/main.go create mode 100644 x-tba/slices/17-copy/02-hacker-incident/main.go create mode 100644 x-tba/slices/18-multi-dimensional-slices/version-1/main.go create mode 100644 x-tba/slices/18-multi-dimensional-slices/version-2/main.go create mode 100644 x-tba/slices/18-multi-dimensional-slices/version-3/main.go create mode 100644 x-tba/slices/19-bouncing-ball-challenge/01-solution-draw-the-board/main.go create mode 100644 x-tba/slices/19-bouncing-ball-challenge/02-solution-drawing-loop/main.go create mode 100644 x-tba/slices/19-bouncing-ball-challenge/03-solution-final/main.go create mode 100644 x-tba/slices/19-bouncing-ball-challenge/04-solution-final-optimize/main.go create mode 100644 x-tba/slices/19-bouncing-ball-challenge/README.md diff --git a/15-slices/05-append/1-theory/main.go b/15-slices/05-append/1-theory/main.go new file mode 100644 index 0000000..572bbcb --- /dev/null +++ b/15-slices/05-append/1-theory/main.go @@ -0,0 +1,39 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + s "github.com/inancgumus/prettyslice" +) + +func main() { + nums := []int{1, 2, 3} + s.Show("nums", nums) + + _ = append(nums, 4) + s.Show("nums", nums) + + nums = append(nums, 4) + s.Show("nums", nums) + + nums = append(nums, 9) + s.Show("nums", nums) + + nums = append(nums, 4) + s.Show("nums", nums) + + // or: + // nums = append(nums, 4, 9) + // s.Show("nums", nums) + + nums = []int{1, 2, 3} + tens := []int{12, 13} + + nums = append(nums, tens...) + s.Show("nums", nums) +} diff --git a/15-slices/05-append/2-example/main.go b/15-slices/05-append/2-example/main.go new file mode 100644 index 0000000..e415fe3 --- /dev/null +++ b/15-slices/05-append/2-example/main.go @@ -0,0 +1,33 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + s "github.com/inancgumus/prettyslice" +) + +func main() { + var todo []string + + todo = append(todo, "sing") + + // you can only append elements with the same element type of the slice + // todo = append(todo, 42) + + todo = append(todo, "run") + + // append is a variadic function, so you can append multiple elements + todo = append(todo, "code", "play") + + // you can also append a slice to another slice using ellipsis: ... + tomorrow := []string{"see mom", "learn go"} + todo = append(todo, tomorrow...) + // todo = append(todo, "see mom", "learn go") + + s.Show("todo", todo) +} diff --git a/15-slices/06-empty-file-finder-project-reading-empty-files/files/empty1.txt b/15-slices/06-empty-file-finder-project-reading-empty-files/files/empty1.txt new file mode 100644 index 0000000..e69de29 diff --git a/15-slices/06-empty-file-finder-project-reading-empty-files/files/empty2.txt b/15-slices/06-empty-file-finder-project-reading-empty-files/files/empty2.txt new file mode 100644 index 0000000..e69de29 diff --git a/15-slices/06-empty-file-finder-project-reading-empty-files/files/empty3.txt b/15-slices/06-empty-file-finder-project-reading-empty-files/files/empty3.txt new file mode 100644 index 0000000..e69de29 diff --git a/15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty1.txt b/15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty1.txt new file mode 100644 index 0000000..1b32b0e --- /dev/null +++ b/15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty1.txt @@ -0,0 +1 @@ +learngoprogramming.com diff --git a/15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty2.txt b/15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty2.txt new file mode 100644 index 0000000..1b32b0e --- /dev/null +++ b/15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty2.txt @@ -0,0 +1 @@ +learngoprogramming.com diff --git a/15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty3.txt b/15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty3.txt new file mode 100644 index 0000000..1b32b0e --- /dev/null +++ b/15-slices/06-empty-file-finder-project-reading-empty-files/files/nonEmpty3.txt @@ -0,0 +1 @@ +learngoprogramming.com diff --git a/15-slices/06-empty-file-finder-project-reading-empty-files/main.go b/15-slices/06-empty-file-finder-project-reading-empty-files/main.go new file mode 100644 index 0000000..b87645a --- /dev/null +++ b/15-slices/06-empty-file-finder-project-reading-empty-files/main.go @@ -0,0 +1,35 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + "io/ioutil" + "os" +) + +func main() { + args := os.Args[1:] + if len(args) == 0 { + fmt.Println("Provide a directory") + return + } + + files, err := ioutil.ReadDir(args[0]) + if err != nil { + fmt.Println(err) + return + } + + for _, file := range files { + if file.Size() == 0 { + name := file.Name() + fmt.Println(name) + } + } +} diff --git a/15-slices/07-empty-file-finder-project-writing-to-a-file/files/empty1.txt b/15-slices/07-empty-file-finder-project-writing-to-a-file/files/empty1.txt new file mode 100644 index 0000000..e69de29 diff --git a/15-slices/07-empty-file-finder-project-writing-to-a-file/files/empty2.txt b/15-slices/07-empty-file-finder-project-writing-to-a-file/files/empty2.txt new file mode 100644 index 0000000..e69de29 diff --git a/15-slices/07-empty-file-finder-project-writing-to-a-file/files/empty3.txt b/15-slices/07-empty-file-finder-project-writing-to-a-file/files/empty3.txt new file mode 100644 index 0000000..e69de29 diff --git a/15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty1.txt b/15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty1.txt new file mode 100644 index 0000000..1b32b0e --- /dev/null +++ b/15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty1.txt @@ -0,0 +1 @@ +learngoprogramming.com diff --git a/15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty2.txt b/15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty2.txt new file mode 100644 index 0000000..1b32b0e --- /dev/null +++ b/15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty2.txt @@ -0,0 +1 @@ +learngoprogramming.com diff --git a/15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty3.txt b/15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty3.txt new file mode 100644 index 0000000..1b32b0e --- /dev/null +++ b/15-slices/07-empty-file-finder-project-writing-to-a-file/files/nonEmpty3.txt @@ -0,0 +1 @@ +learngoprogramming.com diff --git a/15-slices/07-empty-file-finder-project-writing-to-a-file/main.go b/15-slices/07-empty-file-finder-project-writing-to-a-file/main.go new file mode 100644 index 0000000..c397723 --- /dev/null +++ b/15-slices/07-empty-file-finder-project-writing-to-a-file/main.go @@ -0,0 +1,50 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + "io/ioutil" + "os" +) + +func main() { + args := os.Args[1:] + if len(args) == 0 { + fmt.Println("Provide a directory") + return + } + + files, err := ioutil.ReadDir(args[0]) + if err != nil { + fmt.Println(err) + return + } + + var names []byte + + for _, file := range files { + if file.Size() == 0 { + name := file.Name() + + names = append(names, name...) + names = append(names, '\n') + } + } + + err = ioutil.WriteFile("out.txt", names, 0644) + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("%s", names) +} + +// See: https://www.tutorialspoint.com/unix/unix-file-permission.htm +// See: http://permissions-calculator.org/ diff --git a/x-tba/slices/07-slice-expressions/1-theory/main.go b/x-tba/slices/07-slice-expressions/1-theory/main.go new file mode 100644 index 0000000..6951b2b --- /dev/null +++ b/x-tba/slices/07-slice-expressions/1-theory/main.go @@ -0,0 +1,38 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + s "github.com/inancgumus/prettyslice" +) + +func main() { + msg := []byte{'h', 'e', 'l', 'l', 'o'} + s.Show("msg", msg) + + s.Show("msg[0:1]", msg[0:1]) + s.Show("msg[0:2]", msg[0:2]) + s.Show("msg[0:3]", msg[0:3]) + s.Show("msg[0:4]", msg[0:4]) + s.Show("msg[0:5]", msg[0:5]) + + // default indexes + s.Show("msg[0:]", msg[0:]) + s.Show("msg[:5]", msg[:5]) + s.Show("msg[:]", msg[:]) + + // error: beyond + // s.Show("msg", msg)[:6] + + s.Show("msg[1:4]", msg[1:4]) + + s.Show("msg[1:5]", msg[1:5]) + s.Show("msg[1:]", msg[1:]) + + s.Show("append(msg)", append(msg[:4], '!')) +} diff --git a/x-tba/slices/07-slice-expressions/2-example/main.go b/x-tba/slices/07-slice-expressions/2-example/main.go new file mode 100644 index 0000000..b30172b --- /dev/null +++ b/x-tba/slices/07-slice-expressions/2-example/main.go @@ -0,0 +1,59 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + + s "github.com/inancgumus/prettyslice" +) + +func main() { + // think of this as search results of a search engine. + // it could have been fetched from a database + items := []string{ + "pacman", + "mario", + "tetris", + "doom", + "galaga", + "frogger", + "asteroids", + "simcity", + "metroid", + "defender", + "rayman", + "tempest", + "ultima", + } + + s.MaxPerLine = 4 + s.Show("All items", items) + + top3 := items[:3] + s.Show("Top 3 items", top3) + + l := len(items) + + // you can use variables in a slice expression + last4 := items[l-4:] + s.Show("Last 4 items", last4) + + // reslicing: slicing another sliced slice + mid := last4[1:3] + s.Show("Last4[1:3]", mid) + + // the same elements can be in different indexes + // fmt.Println(items[9], last4[0]) + + // slicing returns a slice with the same type of the sliced slice + fmt.Printf("slicing : %T %[1]q\n", items[2:3]) + + // indexing returns a single element with the type of the indexed slice's element type + fmt.Printf("indexing: %T %[1]q\n", items[2]) +} diff --git a/x-tba/slices/08-slice-expressions-pagination/main.go b/x-tba/slices/08-slice-expressions-pagination/main.go new file mode 100644 index 0000000..531407b --- /dev/null +++ b/x-tba/slices/08-slice-expressions-pagination/main.go @@ -0,0 +1,58 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + + s "github.com/inancgumus/prettyslice" +) + +func main() { + // think of this as search results of a search engine. + // it could have been fetched from a database + items := []string{ + "pacman", + "mario", + "tetris", + "doom", + "galaga", + "frogger", + "asteroids", + "simcity", + "metroid", + "defender", + "rayman", + "tempest", + "ultima", + } + + // s.Show("0:4", items[0:4]) + // s.Show("4:8", items[4:8]) + // s.Show("8:12", items[8:12]) + // s.Show("12:13", items[12:13]) + // s.Show("12:14", items[12:14]) // error + + l := len(items) + + const pageSize = 4 + + for from := 0; from < l; from += pageSize { + to := from + pageSize + if to > l { + to = l + } + + // fmt.Printf("%d:%d\n", from, to) + + currentPage := items[from:to] + + head := fmt.Sprintf("Page #%d", (from/pageSize)+1) + s.Show(head, currentPage) + } +} diff --git a/x-tba/slices/09-slice-internals-1-backing-array/1-theory/main.go b/x-tba/slices/09-slice-internals-1-backing-array/1-theory/main.go new file mode 100644 index 0000000..65a7583 --- /dev/null +++ b/x-tba/slices/09-slice-internals-1-backing-array/1-theory/main.go @@ -0,0 +1,44 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import s "github.com/inancgumus/prettyslice" + +func main() { + // ages, first and last2 have the same backing arrays + ages := []int{35, 15, 25} + first := ages[0:1] + last2 := ages[1:3] + + ages[0] = 55 + ages[1] = 10 + ages[2] = 20 + + // grades and ages have separate backing arrays + grades := []int{70, 99} + grades[0] = 50 + + s.Show("ages", ages) + s.Show("ages[0:1]", first) + s.Show("ages[1:3]", last2) + s.Show("grades", grades) + + // let's create a new scope + // 'cause i'm going to use variables with the same name + { + // ages and agesArray have the same backing arrays + agesArray := [3]int{35, 15, 25} + ages := agesArray[0:3] + + ages[0] = 100 + ages[2] = 50 + + s.Show("agesArray", agesArray[:]) + s.Show("agesArray's ages", ages) + } +} diff --git a/x-tba/slices/09-slice-internals-1-backing-array/2-example/main.go b/x-tba/slices/09-slice-internals-1-backing-array/2-example/main.go new file mode 100644 index 0000000..469c747 --- /dev/null +++ b/x-tba/slices/09-slice-internals-1-backing-array/2-example/main.go @@ -0,0 +1,50 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + s "github.com/inancgumus/prettyslice" +) + +func main() { + // #1: arrays and non-empty slice literals create an array. + // For the arrays, it's explicit, but for the slices, + // it's done implicitly, behind the scenes. + + grades := [...]float64{40, 10, 20, 50, 60, 70} // #1 + // grades := []float64{40, 10, 20, 50, 60, 70} // #4 + + // #5: let's break the connection + // #6: comment-out + // var newGrades []float64 + // newGrades = append(newGrades, grades...) + + // #6: shortcut: []float64(nil) is a nil float64 slice + // newGrades := append([]float64(nil), grades...) + + // #2: cheap: slicing doesn't allocate new memory (array). + // front := grades[:3] + + // front := newGrades[:3] // #5 + + // #3: sort its first segment + // sort.Float64s(front) + + // #7: new slices look at the same backing array + // front, front2, front3, newGrades, they all have the same backing array + // front2 := front[:3] + // front3 := front + + s.PrintBacking = true // #1 + s.MaxPerLine = 7 // #1 + s.Show("grades", grades[:]) // #1 + // s.Show("newGrades", newGrades) // #5 + // s.Show("front", front) // #2 + // s.Show("front2", front2) // #7 + // s.Show("front3", front3) // #7 +} diff --git a/x-tba/slices/10-slice-internals-2-slice-header/1-theory/main.go b/x-tba/slices/10-slice-internals-2-slice-header/1-theory/main.go new file mode 100644 index 0000000..2e8303d --- /dev/null +++ b/x-tba/slices/10-slice-internals-2-slice-header/1-theory/main.go @@ -0,0 +1,21 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import s "github.com/inancgumus/prettyslice" + +func main() { + ages := []int{35, 15, 25} + first, last := ages[0:1], ages[1:3] + + s.Show("ages", ages) + s.Show("first", first) + s.Show("last", last) + + s.Show("nil slice", []int(nil)) +} diff --git a/x-tba/slices/10-slice-internals-2-slice-header/2-example/main.go b/x-tba/slices/10-slice-internals-2-slice-header/2-example/main.go new file mode 100644 index 0000000..65f5c70 --- /dev/null +++ b/x-tba/slices/10-slice-internals-2-slice-header/2-example/main.go @@ -0,0 +1,61 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + "unsafe" + + s "github.com/inancgumus/prettyslice" +) + +// type collection [4]string // #1 +type collection []string // #2 + +// go is pass by copy +// only the slice header is copied: 3 integer fields (24 bytes) +// think of passing an array with millions of elements. + +func main() { + // SliceHeader lives here: + // https://golang.org/src/runtime/slice.go + + s.PrintElementAddr = true + + // #1 + data := collection{"slices", "are", "awesome", "period", "!!" /* #5 */} + + // data := collection{"slices", "are", "awesome", "period", "!!"} + + change(data) // #1 + + s.Show("main's data", data) // #1 + fmt.Printf("main's data slice's header: %p\n", &data) // #3 + + // ---------------------------------------------------------------------- + // #4 + array := [...]string{"slices", "are", "awesome", "period", "!!" /* #5 */} + + // array's size depends on its elements + fmt.Printf("array's size: %d bytes.\n", unsafe.Sizeof(array)) + + // slice's size is always fixed: 24 bytes (on a 64-bit system) — slice value = slice header + fmt.Printf("slice's size: %d bytes.\n", unsafe.Sizeof(data)) +} + +// #1 +// passed value will be copied in the function +func change(data collection) { + // data is a new variable inside the function: + // var data collection + + data[2] = "brilliant!" + + s.Show("change's data", data) + fmt.Printf("change's data slice's header: %p\n", &data) // #3 +} diff --git a/x-tba/slices/11-slice-internals-3-len-cap/1-theory/main.go b/x-tba/slices/11-slice-internals-3-len-cap/1-theory/main.go new file mode 100644 index 0000000..e6b3506 --- /dev/null +++ b/x-tba/slices/11-slice-internals-3-len-cap/1-theory/main.go @@ -0,0 +1,31 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + + s "github.com/inancgumus/prettyslice" +) + +func main() { + s.MaxPerLine = 6 + s.PrintBacking = true + + ages := []int{35, 15, 25} + s.Show("ages", ages) + + s.Show("ages[0:0]", ages[0:0]) + + for i := 1; i < 4; i++ { + txt := fmt.Sprintf("ages[%d:%d]", 0, i) + s.Show(txt, ages[0:i]) + } + + s.Show("append", append(ages, 50)) +} diff --git a/x-tba/slices/11-slice-internals-3-len-cap/2-example/main.go b/x-tba/slices/11-slice-internals-3-len-cap/2-example/main.go new file mode 100644 index 0000000..7c43578 --- /dev/null +++ b/x-tba/slices/11-slice-internals-3-len-cap/2-example/main.go @@ -0,0 +1,56 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + s "github.com/inancgumus/prettyslice" +) + +func main() { + s.PrintBacking = true + + // ---------------------------------------------------- + // #1 nil slice + var games []string // nil slice + s.Show("games", games) + + // ---------------------------------------------------- + // #2 empty slice + games = []string{} // empty slice + s.Show("games", games) + // s.Show("another empty", []int{}) + + // ---------------------------------------------------- + // #3 non-empty slice + games = []string{"pacman", "mario", "tetris", "doom"} + s.Show("games", games) + + // ---------------------------------------------------- + // #4 reset the part using the games slice + // part is empty but its cap is still 4 + part := games + s.Show("part", part) + + part = games[:0] + s.Show("part[:0]", part) + s.Show("part[:cap]", part[:cap(part)]) + + for cap(part) != 0 { + part = part[1:cap(part)] + s.Show("part", part) + } + + // #6 backing array's elements become inaccessible + // games = games[len(games):] + + // ---------------------------------------------------- + // #5 part doesn't have any more capacity + // games slice is still intact + s.Show("part", part) + s.Show("games", games) +} diff --git a/x-tba/slices/12-slice-internals-4-append/1-theory/main.go b/x-tba/slices/12-slice-internals-4-append/1-theory/main.go new file mode 100644 index 0000000..7386edb --- /dev/null +++ b/x-tba/slices/12-slice-internals-4-append/1-theory/main.go @@ -0,0 +1,22 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + s "github.com/inancgumus/prettyslice" +) + +func main() { + s.PrintBacking = true + + ages := []int{35, 15} + s.Show("ages", ages) + + ages = append(ages, 5) + s.Show("append(ages, 5)", ages) +} diff --git a/x-tba/slices/12-slice-internals-4-append/2-example/main.go b/x-tba/slices/12-slice-internals-4-append/2-example/main.go new file mode 100644 index 0000000..11a1125 --- /dev/null +++ b/x-tba/slices/12-slice-internals-4-append/2-example/main.go @@ -0,0 +1,54 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + s "github.com/inancgumus/prettyslice" +) + +func main() { + s.PrintBacking = true + + // #1: a nil slice has no backing array + var nums []int + s.Show("no backing array", nums) + + // #2: creates a new backing array + nums = append(nums, 1, 3) + s.Show("allocates", nums) + + // #3: creates a new backing array + nums = append(nums, 2) + s.Show("free capacity", nums) + + // #4: uses the same backing array + nums = append(nums, 4) + s.Show("no allocation", nums) + + // GOAL: append new odd numbers in the middle + // [1 3 2 4] -> [1 3 7 9 2 4] + + // #6: [1 3 2 4] -> [1 3 2 4 2 4] + nums = append(nums, nums[2:]...) + s.Show("nums <- nums[2:]", nums) + + // #5: overwrites: [1 3 2 4 2 4] -> [1 3 7 9] + nums = append(nums[:2], 7, 9) + s.Show("nums[:2] <- 7, 9", nums) + + // #7: [1 3 7 9] -> [1 3 7 9 2 4] + nums = nums[:6] + s.Show("nums: extend", nums) +} + +// don't mind about these options +// they're just for printing the slices nicely +func init() { + s.MaxPerLine = 10 + s.Width = 45 +} diff --git a/x-tba/slices/12-slice-internals-4-append/3-example-growth/main.go b/x-tba/slices/12-slice-internals-4-append/3-example-growth/main.go new file mode 100644 index 0000000..1df92ff --- /dev/null +++ b/x-tba/slices/12-slice-internals-4-append/3-example-growth/main.go @@ -0,0 +1,34 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "math/rand" + "time" + + s "github.com/inancgumus/prettyslice" + "github.com/inancgumus/screen" +) + +func main() { + s.PrintBacking = true + s.MaxPerLine = 30 + s.Width = 150 + + var nums []int + + screen.Clear() + for cap(nums) <= 128 { + screen.MoveTopLeft() + + s.Show("nums", nums) + nums = append(nums, rand.Intn(9)+1) + + time.Sleep(time.Second / 4) + } +} diff --git a/x-tba/slices/12-slice-internals-4-append/4-example-growth/main.go b/x-tba/slices/12-slice-internals-4-append/4-example-growth/main.go new file mode 100644 index 0000000..94b7c1a --- /dev/null +++ b/x-tba/slices/12-slice-internals-4-append/4-example-growth/main.go @@ -0,0 +1,27 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" +) + +func main() { + ages, oldCap := []int{1}, 1. + + for len(ages) < 5e5 { + ages = append(ages, 1) + + c := float64(cap(ages)) + if c != oldCap { + fmt.Printf("len:%-10d cap:%-10g growth:%.2f\n", + len(ages), c, c/oldCap) + } + oldCap = c + } +} diff --git a/x-tba/slices/13-png-parser/1-png-anatomy-format.md b/x-tba/slices/13-png-parser/1-png-anatomy-format.md new file mode 100644 index 0000000..53eb0a8 --- /dev/null +++ b/x-tba/slices/13-png-parser/1-png-anatomy-format.md @@ -0,0 +1,17 @@ +# The Brief Anatomy of a PNG image + +``` +The first 24 bytes: + ++=================================+ +| PNG Header | 8 bytes | -> 137 80 78 71 13 10 26 10 ++---------------------+-----------+ +| IHDR Chunk Header | | +| Chunk Length | 4 bytes | -> The length of the IHDR Chunk Data +| Chunk Type | 4 bytes | -> 73 72 68 82 ++---------------------+-----------+ +| IHDR Chunk Data | | +| Width | 4 bytes | -> Unsigned 32-bit integer +| Height | 4 bytes | -> Unsigned 32-bit integer ++=================================+ +``` \ No newline at end of file diff --git a/x-tba/slices/13-png-parser/2-png-anatomy-example.md b/x-tba/slices/13-png-parser/2-png-anatomy-example.md new file mode 100644 index 0000000..7d4df1a --- /dev/null +++ b/x-tba/slices/13-png-parser/2-png-anatomy-example.md @@ -0,0 +1,26 @@ +# The Brief Anatomy of a PNG image + +``` +The first 24 bytes: + +PNG HEADER: +╔═════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗╔════╗ +║ 137 ║║ 80 ║║ 78 ║║ 71 ║║ 13 ║║ 10 ║║ 26 ║║ 10 ║ +╚═════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝╚════╝ + 0 1 2 3 4 5 6 7 + +CHUNK LENGTH CHUNK TYPE (IHDR) +╔═══╗╔═══╗╔═══╗╔════╗╔════╗╔════╗╔════╗╔════╗ +║ 0 ║║ 0 ║║ 0 ║║ 13 ║║ 73 ║║ 72 ║║ 68 ║║ 82 ║ +╚═══╝╚═══╝╚═══╝╚════╝╚════╝╚════╝╚════╝╚════╝ + 8 9 10 11 12 13 14 15 + +( Unsigned 32-bit integers ) +WIDTH HEIGHT +╔═══╗╔═══╗╔═══╗╔════╗╔═══╗╔═══╗╔═══╗╔════╗ +║ 0 ║║ 0 ║║ 2 ║║ 76 ║║ 0 ║║ 0 ║║ 3 ║║ 32 ║ +╚═══╝╚═══╝╚═══╝╚════╝╚═══╝╚═══╝╚═══╝╚════╝ + 16 17 18 19 20 21 22 23 + +... Other bytes in the png image ... +``` \ No newline at end of file diff --git a/x-tba/slices/13-png-parser/images/broken-missing-ihdr.png b/x-tba/slices/13-png-parser/images/broken-missing-ihdr.png new file mode 100644 index 0000000..7def385 --- /dev/null +++ b/x-tba/slices/13-png-parser/images/broken-missing-ihdr.png @@ -0,0 +1,5 @@ +PNG + +/}P̒>0jȂ&✉\@TLU +x/ +Z`w;9c \ No newline at end of file diff --git a/x-tba/slices/13-png-parser/images/broken-missing-png-header.png b/x-tba/slices/13-png-parser/images/broken-missing-png-header.png new file mode 100644 index 0000000000000000000000000000000000000000..45237a1d294f7432c06ae45769727d9745250221 GIT binary patch literal 164 zcmeAS@Jr|AlHy`uVBq!ia0vp^3Lwk~Bp9L@-6Me%OS+@4BLidG0>c;6;z7cmE{-7; zb9B#azopr0E~z=2mk;8 literal 0 HcmV?d00001 diff --git a/x-tba/slices/13-png-parser/images/gopher.png b/x-tba/slices/13-png-parser/images/gopher.png new file mode 100644 index 0000000000000000000000000000000000000000..85987235a9a6b188cb3d87c054627b3a42b73815 GIT binary patch literal 67555 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

?I}B^d)4zQ(t#a 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 literal 0 HcmV?d00001 diff --git a/x-tba/slices/13-png-parser/main.go b/x-tba/slices/13-png-parser/main.go new file mode 100644 index 0000000..6431060 --- /dev/null +++ b/x-tba/slices/13-png-parser/main.go @@ -0,0 +1,86 @@ +package main + +import ( + "bytes" + "encoding/binary" + "fmt" + "io/ioutil" + "os" + + ps "github.com/inancgumus/prettyslice" +) + +func main() { + var ( + pngHeader = [...]byte{137, 80, 78, 71, 13, 10, 26, 10} + ihdrChunkType = [...]byte{73, 72, 68, 82} + ) + + args := os.Args[1:] + if len(args) == 0 { + fmt.Println("run with a PNG file") + return + } + + // this is not the best way + // it's better only to read the first 24 bytes + // this reads the whole file into memory + img, err := ioutil.ReadFile(args[0]) + if err != nil { + fmt.Println(err) + return + } + + // limit the capacity to prevent the errors downward + // 'cause we only need the first 24 bytes + img = img[:24:24] + // ps.Show("first 24 bytes", img) + + // ------------------------------------------ + // Read the PNG header + // https://www.w3.org/TR/2003/REC-PNG-20031110/#5PNG-file-signature + // ------------------------------------------ + lpng := len(pngHeader) + if !bytes.Equal(img[:lpng], pngHeader[:]) { + fmt.Println("missing PNG header") + return + } + + // skip the png header + img = img[lpng:] + + // ------------------------------------------ + // Read the IHDR chunk header + // The IHDR chunk shall be the first chunk in the PNG datastream. + // https://www.w3.org/TR/2003/REC-PNG-20031110/#11IHDR + // ------------------------------------------ + header := img[:8] // get the length and chunk type + + // ensure that the chunk type is IHDR + if !bytes.Equal(header[4:8], ihdrChunkType[:]) { + fmt.Println("missing IHDR chunk") + return + } + + // ------------------------------------------ + // Read the IHDR Chunk Data + // ------------------------------------------ + img = img[len(header):] // skip the IHDR chunk header data + ihdr := img[:8] // read the width&height from the ihdr chunk + + // All integers that require more than one byte shall be in: + // network byte order = Big Endian + // https://www.w3.org/TR/2003/REC-PNG-20031110/#7Integers-and-byte-order + fmt.Printf("dimensions: %dx%d\n", + // read the first 4 bytes (width) + binary.BigEndian.Uint32(ihdr[:4]), + // read the next 4 bytes (height) + binary.BigEndian.Uint32(ihdr[4:8])) +} + +func init() { + ps.PrintBacking = true + ps.PrettyByteRune = false + ps.MaxPerLine = 8 + ps.MaxElements = 32 +} diff --git a/x-tba/slices/14-full-slice-expressions/1-theory/main.go b/x-tba/slices/14-full-slice-expressions/1-theory/main.go new file mode 100644 index 0000000..213a1a3 --- /dev/null +++ b/x-tba/slices/14-full-slice-expressions/1-theory/main.go @@ -0,0 +1,28 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + s "github.com/inancgumus/prettyslice" +) + +func main() { + s.PrintBacking = true + + sliceable := []byte{'f', 'u', 'l', 'l'} + + s.Show("sliceable", sliceable) + s.Show("sliceable[0:3]", sliceable[0:3]) + s.Show("sliceable[0:3:3]", sliceable[0:3:3]) + s.Show("sliceable[0:2:2]", sliceable[0:2:2]) + s.Show("sliceable[0:1:1]", sliceable[0:1:1]) + s.Show("sliceable[1:3:3]", sliceable[1:3:3]) + s.Show("sliceable[2:3:3]", sliceable[2:3:3]) + s.Show("sliceable[2:3:4]", sliceable[2:3:4]) + s.Show("sliceable[4:4:4]", sliceable[4:4:4]) +} diff --git a/x-tba/slices/14-full-slice-expressions/2-example/main.go b/x-tba/slices/14-full-slice-expressions/2-example/main.go new file mode 100644 index 0000000..42ac6f5 --- /dev/null +++ b/x-tba/slices/14-full-slice-expressions/2-example/main.go @@ -0,0 +1,35 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + s "github.com/inancgumus/prettyslice" +) + +func main() { + s.PrintBacking = true + + nums := []int{1, 3, 2, 4} // #1 + // odds := nums[:2] // #2 + // odds := nums[:2:2] // #4 + // odds = append(odds, 5, 7) // #3 + + // odds := append(nums[:2:2], 5, 7) // #5 + // evens := append(nums[2:4], 6, 8) // #6 + + s.Show("nums", nums) // #1 + // s.Show("odds", odds) // #2 + // s.Show("evens", evens) // #6 +} + +// don't mind about these options +// they're just for printing the slices nicely +func init() { + s.MaxPerLine = 10 + s.Width = 55 +} diff --git a/x-tba/slices/15-make/1-theory/main.go b/x-tba/slices/15-make/1-theory/main.go new file mode 100644 index 0000000..89f7abf --- /dev/null +++ b/x-tba/slices/15-make/1-theory/main.go @@ -0,0 +1,25 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + prettyslice "github.com/inancgumus/prettyslice" +) + +func main() { + prettyslice.PrintBacking = true + + prettyslice.Show("make([]int, 3)", make([]int, 3)) + prettyslice.Show("make([]int, 3, 5)", make([]int, 3, 5)) + + s := make([]int, 0, 5) + prettyslice.Show("make([]int, 0, 5)", s) + + s = append(s, 42) + prettyslice.Show("s = append(s, 42)", s) +} diff --git a/x-tba/slices/15-make/2-example/main.go b/x-tba/slices/15-make/2-example/main.go new file mode 100644 index 0000000..0038f93 --- /dev/null +++ b/x-tba/slices/15-make/2-example/main.go @@ -0,0 +1,83 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "strings" + + s "github.com/inancgumus/prettyslice" +) + +func main() { + s.PrintBacking = true + s.MaxPerLine = 10 + + // #1: assume that tasks can be a long list + // --------------------------------------------- + tasks := []string{"jump", "run", "read"} + + // #2: INEFFICIENT WAY + // --------------------------------------------- + // var upTasks []string + // s.Show("upTasks", upTasks) + + // for _, task := range tasks { + // upTasks = append(upTasks, strings.ToUpper(task)) + // s.Show("upTasks", upTasks) + // } + + // #3: SO SO WAY: + // --------------------------------------------- + // upTasks := make([]string, len(tasks)) + // s.Show("upTasks", upTasks) + + // for _, task := range tasks { + // upTasks = append(upTasks, strings.ToUpper(task)) + // s.Show("upTasks", upTasks) + // } + + // #4: SO SO WAY 2: + // --------------------------------------------- + // upTasks := make([]string, len(tasks)) + // s.Show("upTasks", upTasks) + + // for i, task := range tasks { + // upTasks[i] = strings.ToUpper(task) + // s.Show("upTasks", upTasks) + // } + + // #5: allocates a new array + // upTasks = append(upTasks, "PLAY") + // s.Show("upTasks", upTasks) + + // #6: SO SO WAY 3 + // --------------------------------------------- + // upTasks := make([]string, 0, len(tasks)) + + // #7 + // upTasks = upTasks[:cap(upTasks)] + + // #6 + // s.Show("upTasks", upTasks) + + // for i, task := range tasks { + // upTasks[i] = strings.ToUpper(task) + // s.Show("upTasks", upTasks) + // } + + // #8: THE BEST WAY + // --------------------------------------------- + upTasks := make([]string, 0, len(tasks)) + + s.Show("upTasks", upTasks) + + for _, task := range tasks { + upTasks = append(upTasks, strings.ToUpper(task)) + s.Show("upTasks", upTasks) + } +} diff --git a/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/empty1.txt b/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/empty1.txt new file mode 100644 index 0000000..e69de29 diff --git a/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/empty2.txt b/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/empty2.txt new file mode 100644 index 0000000..e69de29 diff --git a/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/empty3.txt b/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/empty3.txt new file mode 100644 index 0000000..e69de29 diff --git a/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty1.txt b/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty1.txt new file mode 100644 index 0000000..1b32b0e --- /dev/null +++ b/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty1.txt @@ -0,0 +1 @@ +learngoprogramming.com diff --git a/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty2.txt b/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty2.txt new file mode 100644 index 0000000..1b32b0e --- /dev/null +++ b/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty2.txt @@ -0,0 +1 @@ +learngoprogramming.com diff --git a/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty3.txt b/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty3.txt new file mode 100644 index 0000000..1b32b0e --- /dev/null +++ b/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/files/nonEmpty3.txt @@ -0,0 +1 @@ +learngoprogramming.com diff --git a/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/main.go b/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/main.go new file mode 100644 index 0000000..4fc0fa3 --- /dev/null +++ b/x-tba/slices/16-empty-file-finder-project-optimize/version-3-optimize/main.go @@ -0,0 +1,70 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + "io/ioutil" + "os" +) + +// You can easily write to a file using bash. +// +// However, when what you're creating is a library, +// then you won't have that option. So, it's good to learn +// how to write to a file using a byte slice. + +// ioutil.ReadDir +// os.FileInfo + +func main() { + args := os.Args[1:] + if len(args) == 0 { + fmt.Println("Provide a directory") + return + } + + files, err := ioutil.ReadDir(args[0]) + if err != nil { + fmt.Println(err) + return + } + + // 1st: find the total size of all the empty files + var total int + for _, file := range files { + if file.Size() == 0 { + // +1 for the newline character + // when printing the filename + total += len(file.Name()) + 1 + } + } + + // 2nd: allocate a large enough byte slice in one go + names := make([]byte, 0, total) + + for _, file := range files { + if file.Size() == 0 { + name := file.Name() + + names = append(names, name...) + names = append(names, '\n') + } + } + + err = ioutil.WriteFile("out.txt", names, 0644) + if err != nil { + fmt.Println(err) + return + } + + fmt.Printf("%s", names) +} + +// See: https://www.tutorialspoint.com/unix/unix-file-permission.htm +// See: http://permissions-calculator.org/ diff --git a/x-tba/slices/17-copy/01-usage/main.go b/x-tba/slices/17-copy/01-usage/main.go new file mode 100644 index 0000000..537622e --- /dev/null +++ b/x-tba/slices/17-copy/01-usage/main.go @@ -0,0 +1,28 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + + s "github.com/inancgumus/prettyslice" +) + +func main() { + evens := []int{2, 4} + odds := []int{3, 5, 7} + + s.Show("evens [before]", evens) + s.Show("odds [before]", odds) + + N := copy(evens, odds) + fmt.Printf("%d element(s) are copied.\n", N) + + s.Show("evens [after]", evens) + s.Show("odds [after]", odds) +} diff --git a/x-tba/slices/17-copy/02-hacker-incident/main.go b/x-tba/slices/17-copy/02-hacker-incident/main.go new file mode 100644 index 0000000..31df908 --- /dev/null +++ b/x-tba/slices/17-copy/02-hacker-incident/main.go @@ -0,0 +1,56 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + + s "github.com/inancgumus/prettyslice" +) + +func main() { + // #1: received the raining probabilities + data := []float64{10, 25, 30, 50} + + // #2: received new data + // newData := []float64{80, 90} + // for i := 0; i < len(newData); i++ { + // data[i] = newData[i] + // } + + // #3: use copy + // copy(data, []float64{99, 100}) + + // #4: received more data than the original + // copy(data, []float64{10, 5, 15, 0, 20}) + + // #5: returns the # of copied elements + // n := copy(data, []float64{10, 5, 15, 0, 20}) + // fmt.Printf("%d probabilities copied.\n", n) + + // #6: (sometimes) use append instead of copy + // data = append(data[:0], []float64{10, 5, 15, 0, 20}...) + + // #7: clone a slice using copy + // saved := make([]float64, len(data)) + // copy(saved, data) + + // #9: clone a slice using append nil (i prefer this) + // saved := append([]float64(nil), data...) + + // data[0] = 0 // #8 + + // s.Show("Probabilities (saved)", saved) // #7 + + // #1: print the probabilities + s.Show("Probabilities (data)", data) + + fmt.Printf("Is it gonna rain? %.f%% chance.\n", + (data[0]+data[1]+data[2]+data[3])/ + float64(len(data))) +} diff --git a/x-tba/slices/18-multi-dimensional-slices/version-1/main.go b/x-tba/slices/18-multi-dimensional-slices/version-1/main.go new file mode 100644 index 0000000..0e351d4 --- /dev/null +++ b/x-tba/slices/18-multi-dimensional-slices/version-1/main.go @@ -0,0 +1,33 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" +) + +func main() { + // 1st day: $200, $100 + // 2nd day: $500 + // 3rd day: $50, $25, and $75 + + spendings := [][]int{ + {200, 100}, // 1st day + {500}, // 2nd day + {50, 25, 75}, // 3rd day + } + + for i, daily := range spendings { + var total int + for _, spending := range daily { + total += spending + } + + fmt.Printf("Day %d: %d\n", i+1, total) + } +} diff --git a/x-tba/slices/18-multi-dimensional-slices/version-2/main.go b/x-tba/slices/18-multi-dimensional-slices/version-2/main.go new file mode 100644 index 0000000..74acd8f --- /dev/null +++ b/x-tba/slices/18-multi-dimensional-slices/version-2/main.go @@ -0,0 +1,30 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" +) + +func main() { + spendings := make([][]int, 0, 5) + + spendings = append(spendings, []int{200, 100}) + spendings = append(spendings, []int{25, 10, 45, 60}) + spendings = append(spendings, []int{5, 15, 35}) + spendings = append(spendings, []int{95, 10}, []int{50, 25}) + + for i, daily := range spendings { + var total int + for _, spending := range daily { + total += spending + } + + fmt.Printf("Day %d: %d\n", i+1, total) + } +} diff --git a/x-tba/slices/18-multi-dimensional-slices/version-3/main.go b/x-tba/slices/18-multi-dimensional-slices/version-3/main.go new file mode 100644 index 0000000..b1cf865 --- /dev/null +++ b/x-tba/slices/18-multi-dimensional-slices/version-3/main.go @@ -0,0 +1,52 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + "strconv" + "strings" +) + +func main() { + spendings := fetch() + + for i, daily := range spendings { + var total int + for _, spending := range daily { + total += spending + } + + fmt.Printf("Day %d: %d\n", i+1, total) + } +} + +func fetch() [][]int { + content := `200 100 +25 10 45 60 +5 15 35 +95 10 +50 25` + + lines := strings.Split(content, "\n") + + spendings := make([][]int, len(lines)) + + for i, line := range lines { + fields := strings.Fields(line) + + spendings[i] = make([]int, len(fields)) + + for j, field := range fields { + spending, _ := strconv.Atoi(field) + spendings[i][j] = spending + } + } + + return spendings +} diff --git a/x-tba/slices/19-bouncing-ball-challenge/01-solution-draw-the-board/main.go b/x-tba/slices/19-bouncing-ball-challenge/01-solution-draw-the-board/main.go new file mode 100644 index 0000000..8e2897b --- /dev/null +++ b/x-tba/slices/19-bouncing-ball-challenge/01-solution-draw-the-board/main.go @@ -0,0 +1,47 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" +) + +const ( + width = 25 + height = 8 +) + +func main() { + // ------------------------------------------------- + // CREATE THE BOARD + // ------------------------------------------------- + board := make([][]bool, width) + for row := range board { + board[row] = make([]bool, height) + } + + // ------------------------------------------------- + // DRAW THE BOARD + // ------------------------------------------------- + var ( + buf = make([]rune, 0, width*height) + ball rune + ) + + for y := range board[0] { + for x := range board { + ball = '🎱' + if board[x][y] { + ball = '🎾' + } + buf = append(buf, ball, ' ') + } + buf = append(buf, '\n') + } + fmt.Print(string(buf)) +} diff --git a/x-tba/slices/19-bouncing-ball-challenge/02-solution-drawing-loop/main.go b/x-tba/slices/19-bouncing-ball-challenge/02-solution-drawing-loop/main.go new file mode 100644 index 0000000..1eca517 --- /dev/null +++ b/x-tba/slices/19-bouncing-ball-challenge/02-solution-drawing-loop/main.go @@ -0,0 +1,68 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + "time" + + "github.com/inancgumus/screen" +) + +const ( + width = 25 + height = 8 + + maxFrames = 1200 +) + +func main() { + // ------------------------------------------------- + // CREATE THE BOARD + // ------------------------------------------------- + board := make([][]bool, width) + for row := range board { + board[row] = make([]bool, height) + } + + var X, Y int // ball positions + + screen.Clear() + + for i := 0; i < maxFrames; i++ { + // ------------------------------------------------- + // PUT THE BALL + // ------------------------------------------------- + board[X][Y] = true + + // ------------------------------------------------- + // DRAW THE BOARD + // ------------------------------------------------- + var ( + buf = make([]rune, 0, width*height) + ball rune + ) + + for y := range board[0] { + for x := range board { + ball = '🎱' + if board[x][y] { + ball = '🎾' + } + buf = append(buf, ball, ' ') + } + buf = append(buf, '\n') + } + + screen.MoveTopLeft() + fmt.Print(string(buf)) + + // draw after a while: slows down the animation + time.Sleep(time.Second / 20) + } +} diff --git a/x-tba/slices/19-bouncing-ball-challenge/03-solution-final/main.go b/x-tba/slices/19-bouncing-ball-challenge/03-solution-final/main.go new file mode 100644 index 0000000..c43b41c --- /dev/null +++ b/x-tba/slices/19-bouncing-ball-challenge/03-solution-final/main.go @@ -0,0 +1,94 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + "time" + + "github.com/inancgumus/screen" +) + +const ( + width = 25 + height = 8 + + maxFrames = 1200 +) + +func main() { + // ------------------------------------------------- + // CREATE THE BOARD + // ------------------------------------------------- + board := make([][]bool, width) + for row := range board { + board[row] = make([]bool, height) + } + + var ( + X, Y int // ball positions + xVel, yVel = 1, 1 // velocities + ) + + screen.Clear() + + for i := 0; i < maxFrames; i++ { + // ------------------------------------------------- + // CALCULATE THE NEXT BALL POSITION + // ------------------------------------------------- + X += xVel + Y += yVel + + // when the ball hits the borders change its direction + // by changing its velocity + if X <= 0 || X >= width-1 { + xVel *= -1 + } + if Y <= 0 || Y >= height-1 { + yVel *= -1 + } + + // ------------------------------------------------- + // CLEAR THE BOARD AND PUT THE BALL + // ------------------------------------------------- + for y := range board[0] { + for x := range board { + board[x][y] = false + } + } + board[X][Y] = true + + // ------------------------------------------------- + // DRAW THE BOARD + // ------------------------------------------------- + var ( + buf = make([]rune, 0, width*height) + ball rune + ) + + for y := range board[0] { + for x := range board { + ball = '🎱' + if board[x][y] { + ball = '🎾' + } + buf = append(buf, ball, ' ') + } + buf = append(buf, '\n') + } + + // clear the screen and draw the board + screen.MoveTopLeft() + fmt.Print(string(buf)) + + // TODO: in the notes this is at the beginning of the loop + + // draw after a while: slows down the animation + time.Sleep(time.Second / 20) + } +} diff --git a/x-tba/slices/19-bouncing-ball-challenge/04-solution-final-optimize/main.go b/x-tba/slices/19-bouncing-ball-challenge/04-solution-final-optimize/main.go new file mode 100644 index 0000000..5d1c854 --- /dev/null +++ b/x-tba/slices/19-bouncing-ball-challenge/04-solution-final-optimize/main.go @@ -0,0 +1,92 @@ +// For more tutorials: https://blog.learngoprogramming.com +// +// Copyright © 2018 Inanc Gumus +// Learn Go Programming Course +// License: https://creativecommons.org/licenses/by-nc-sa/4.0/ +// + +package main + +import ( + "fmt" + "time" + + "github.com/inancgumus/screen" +) + +const ( + width = 25 + height = 8 + + maxFrames = 1200 +) + +func main() { + // ------------------------------------------------- + // CREATE THE BOARD + // ------------------------------------------------- + board := make([][]bool, width) + for row := range board { + board[row] = make([]bool, height) + } + + var ( + X, Y int // ball positions + pX, pY int // previous ball positions (for clearing) + xVel, yVel = 1, 1 // velocities + + buf [width * height]rune // drawing buffer + ) + + screen.Clear() + + for i := 0; i < maxFrames; i++ { + // ------------------------------------------------- + // CALCULATE THE NEXT BALL POSITION + // ------------------------------------------------- + X += xVel + Y += yVel + + // when the ball hits the borders change its direction + // by changing its velocity + if X <= 0 || X >= width-1 { + xVel *= -1 + } + if Y <= 0 || Y >= height-1 { + yVel *= -1 + } + + // ------------------------------------------------- + // PUT THE BALL AND CLEAR THE BOARD + // ------------------------------------------------- + board[X][Y] = true + board[pX][pY] = false + pX, pY = X, Y + + // ------------------------------------------------- + // DRAW THE BOARD + // ------------------------------------------------- + var ball rune + + // rewind the buffer + bufs := buf[:] + + for y := range board[0] { + for x := range board { + ball = ' ' + if board[x][y] { + ball = '🎾' + } + bufs = append(bufs, ball, ' ') + } + bufs = append(bufs, '\n') + } + + // clear the screen and draw the board + screen.MoveTopLeft() + fmt.Print(string(bufs)) + + // draw after a while: slows down the animation + time.Sleep(time.Second / 20) + } +} diff --git a/x-tba/slices/19-bouncing-ball-challenge/README.md b/x-tba/slices/19-bouncing-ball-challenge/README.md new file mode 100644 index 0000000..90bdc42 --- /dev/null +++ b/x-tba/slices/19-bouncing-ball-challenge/README.md @@ -0,0 +1,166 @@ +# Bouncing Ball Challenge + +This document contains what you need to do to create the bouncing ball animation.You're going to learn a great deal of knowledge about slices and you'll gain a good experience while doing this. + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## Declare the constants +* The width and the height of the board. + +* It can be anything, just experiment. + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## Declare the ball positions and velocity: +The ball should be in a known position on your board, and it should have a velocity. + +* **Velocity means: Speed and Direction** + + * X velocity = 1 -> _ball moves right_ + * X velocity = -1 -> _ball moves left_ + * Y velocity = 1 -> _ball moves down_ + * Y velocity = -1 -> _ball moves up_ + +* Declare variables for the ball's positions: `X` and `Y` + +* Declare variables for the ball's velocity: `xVelocity` and `yVelocity` + +* On each step: Add velocities to ball's position. This will make the ball move. + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## 🎾 CREATE THE BOARD + +You can use a multi-dimensional bool slice to create the board. Each element in the slice corresponds to whether the ball is in that element (or position) or not. + +* Use the `make` function to initialize your board. + + * Remember: Zero value for a slice is `nil`. + * So, you need to initialize each sub-slice of the board slice. + +* You can use `[][]bool` for your board. + + * It's because, when you set one of the elements to true, then you'd know that the ball is in that position. + + * *EXAMPLE:* + ``` + false false false false + false true -+ false false + false false | false false + v + the ball is here + board[1][1] is true + ``` + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## 🎾 CLEAR THE SCREEN + +* Before the loop, clear the screen once by using the screen package. + +* It's [here](https://github.com/inancgumus/screen). +* Its documentation is [here](https://godoc.org/github.com/inancgumus/screen). + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## 🎾 DRAWING LOOP +This is the main loop that will draw the board and the ball to the screen continuously. + +* Create the loop + +* On each step of the loop, you're going to: + * Clear the board + * Calculate the next ball position + * Draw the board and the balls + +Explanations for these steps follow... + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## 🎾 CLEAR THE BOARD +At the beginning your board should not contain the ball. + +* So, set all the inner slices of the board slice to `false`. + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## 🎾 CALCULATE THE NEXT BALL POSITION +You need to calculate the ball's next position on the board. + +* Add the velocities to the ball's current position: + + * `X += xVelocity` + * `Y += yVelocity` + +* When the ball hits the borders of the board change its direction. + + * **HINT:** You can multiply any velocity by `-1` to change its direction. + +* Set the ball's position on the board. + + * You will use this information when drawing the board. + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## 🎾 DRAW THE BOARD +Instead of drawing the board and the ball to the screen everytime, you will fill a buffer, and when you complete, you will draw the whole board and the ball once by printing the buffer that you filled. + +* Make a large enough rune slice named `buf` using the `make` function. + +* **HINT:** `width * height` will give you a large enough buffer. + +* **TIP:** You could also use `string` concatenation but it would be inefficient. + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## FILL YOUR BUFFER: + +* Filling your buffer: + + * Loop for the height of the board (_described below_). + + * Then in a nested loop (_described below_), loop for the width of the board. + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## NESTEP LOOP: WIDTH LOOP +* On each step of the nested loop, do this: + + * Check whether the ball is in the x, y positions. + * You need to check for it using your board slice. + + * If so, `append` this tennis ball '🎾' to the buffer. + * If not, `append` this pool ball '🎱' to the buffer. + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## NESTEP LOOP: HEIGHT LOOP + +* After the nested loop (but in the height loop): + +* `append` the newline character to the buffer: `'\n'` + * This will allow you to print the next row to the next line. + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## 🎾 MOVE THE CURSOR + +* After the loop, move the cursor to the top-left position by using the screen package. + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## PRINT THE BOARD (USING THE BUFFER): + +* Do not forget converting it to `string`. Because your buffer is `[]rune`, like so: + + `fmt.Print(string(buf))` + +* You'll learn the details about rune and strings later. + +➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖➖ + +## SLOW DOWN THE SPEED + +And lastly, call the `time.Sleep` function to slow down the speed of the loop, so you can see the ball :) Like so: + + `time.Sleep(time.Millisecond * 60)`