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 0000000..45237a1 Binary files /dev/null and b/x-tba/slices/13-png-parser/images/broken-missing-png-header.png differ 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 0000000..8598723 Binary files /dev/null and b/x-tba/slices/13-png-parser/images/gopher.png differ 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)`