From b0efd28975bf3d185e495c2b4bd58b2ca2f83ab6 Mon Sep 17 00:00:00 2001 From: Inanc Gumus Date: Fri, 22 Mar 2019 13:57:20 +0300 Subject: [PATCH] fix: bouncing ball exercises --- .../exercises/01-find-the-bug/main.go | 119 ++++++++++++++++++ .../01-find-the-bug/solution/main.go | 99 +++++++++++++++ .../main.go | 26 ++-- .../solution/main.go | 7 +- .../main.go | 7 +- .../solution/main.go | 20 +-- .../main.go | 20 +-- .../solution/main.go | 37 +++--- 8 files changed, 292 insertions(+), 43 deletions(-) create mode 100644 18-project-bouncing-ball/exercises/01-find-the-bug/main.go create mode 100644 18-project-bouncing-ball/exercises/01-find-the-bug/solution/main.go rename 18-project-bouncing-ball/exercises/{01-width-and-height => 02-width-and-height}/main.go (96%) rename 18-project-bouncing-ball/exercises/{01-width-and-height => 02-width-and-height}/solution/main.go (93%) rename 18-project-bouncing-ball/exercises/{02-previous-positions => 03-previous-positions}/main.go (94%) rename 18-project-bouncing-ball/exercises/{02-previous-positions => 03-previous-positions}/solution/main.go (82%) rename 18-project-bouncing-ball/exercises/{03-single-dimensional => 04-single-dimensional}/main.go (86%) rename 18-project-bouncing-ball/exercises/{03-single-dimensional => 04-single-dimensional}/solution/main.go (71%) diff --git a/18-project-bouncing-ball/exercises/01-find-the-bug/main.go b/18-project-bouncing-ball/exercises/01-find-the-bug/main.go new file mode 100644 index 0000000..a7cbb05 --- /dev/null +++ b/18-project-bouncing-ball/exercises/01-find-the-bug/main.go @@ -0,0 +1,119 @@ +// 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" +) + +// --------------------------------------------------------- +// EXERCISE: Find the Bug +// +// As I've annotated in the lectures, there is a bug +// in this code. Please find the bug and fix it. +// +// +// HINT #1 +// +// 💀 Read this only if you get stuck. +// +// Print the width*height and the capacity of the drawing buffer +// after a single drawing loop ends. You might be surprised. +// +// +// HINT #2 +// +// 💀 Read this only if you get stuck. +// +// The bug is in the drawing buffer. It doesn't include the +// newline and space characters when creating the buffer. So +// the buffer is not large enough to hold all the characters. +// So new backing arrays are getting allocated. +// +// --------------------------------------------------------- + +func main() { + const ( + width = 50 + height = 10 + + cellEmpty = ' ' + cellBall = '⚾' + + maxFrames = 1200 + speed = time.Second / 20 + ) + + var ( + px, py int // ball position + vx, vy = 1, 1 // velocities + + cell rune // current cell (for caching) + ) + + // create the board + board := make([][]bool, width) + for column := range board { + board[column] = make([]bool, height) + } + + // create a drawing buffer + buf := make([]rune, 0, width*height) + + // clear the screen once + screen.Clear() + + for i := 0; i < maxFrames; i++ { + // calculate the next ball position + px += vx + py += vy + + // when the ball hits a border reverse its direction + if px <= 0 || px >= width-1 { + vx *= -1 + } + if py <= 0 || py >= height-1 { + vy *= -1 + } + + // remove the previous ball + for y := range board[0] { + for x := range board { + board[x][y] = false + } + } + + // put the new ball + board[px][py] = true + + // rewind the buffer (allow appending from the beginning) + buf = buf[:0] + + // draw the board into the buffer + for y := range board[0] { + for x := range board { + cell = cellEmpty + if board[x][y] { + cell = cellBall + } + buf = append(buf, cell, ' ') + } + buf = append(buf, '\n') + } + + // print the buffer + screen.MoveTopLeft() + fmt.Print(string(buf)) + + // slow down the animation + time.Sleep(speed) + } +} diff --git a/18-project-bouncing-ball/exercises/01-find-the-bug/solution/main.go b/18-project-bouncing-ball/exercises/01-find-the-bug/solution/main.go new file mode 100644 index 0000000..7d02104 --- /dev/null +++ b/18-project-bouncing-ball/exercises/01-find-the-bug/solution/main.go @@ -0,0 +1,99 @@ +// 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" +) + +func main() { + const ( + width = 50 + height = 10 + + cellEmpty = ' ' + cellBall = '⚾' + + maxFrames = 1200 + speed = time.Second / 20 + + // drawing buffer length + // *2 for extra spaces + // +1 for newlines + bufLen = (width*2 + 1) * height + ) + + var ( + px, py int // ball position + vx, vy = 1, 1 // velocities + + cell rune // current cell (for caching) + ) + + // create the board + board := make([][]bool, width) + for column := range board { + board[column] = make([]bool, height) + } + + // create a drawing buffer + // BUG FIXED! + buf := make([]rune, 0, bufLen) + + // clear the screen once + screen.Clear() + + for i := 0; i < maxFrames; i++ { + // calculate the next ball position + px += vx + py += vy + + // when the ball hits a border reverse its direction + if px <= 0 || px >= width-1 { + vx *= -1 + } + if py <= 0 || py >= height-1 { + vy *= -1 + } + + // remove the previous ball + for y := range board[0] { + for x := range board { + board[x][y] = false + } + } + + // put the new ball + board[px][py] = true + + // rewind the buffer (allow appending from the beginning) + buf = buf[:0] + + // draw the board into the buffer + for y := range board[0] { + for x := range board { + cell = cellEmpty + if board[x][y] { + cell = cellBall + } + buf = append(buf, cell, ' ') + } + buf = append(buf, '\n') + } + + // print the buffer + screen.MoveTopLeft() + fmt.Print(string(buf)) + + // slow down the animation + time.Sleep(speed) + } +} diff --git a/18-project-bouncing-ball/exercises/01-width-and-height/main.go b/18-project-bouncing-ball/exercises/02-width-and-height/main.go similarity index 96% rename from 18-project-bouncing-ball/exercises/01-width-and-height/main.go rename to 18-project-bouncing-ball/exercises/02-width-and-height/main.go index a130187..b10a1d4 100644 --- a/18-project-bouncing-ball/exercises/01-width-and-height/main.go +++ b/18-project-bouncing-ball/exercises/02-width-and-height/main.go @@ -5,6 +5,15 @@ // License: https://creativecommons.org/licenses/by-nc-sa/4.0/ // +package main + +import ( + "fmt" + "time" + + "github.com/inancgumus/screen" +) + // --------------------------------------------------------- // EXERCISE: Adjust the width and height automatically // @@ -88,15 +97,6 @@ // // --------------------------------------------------------- -package main - -import ( - "fmt" - "time" - - "github.com/inancgumus/screen" -) - func main() { const ( width = 50 @@ -107,6 +107,12 @@ func main() { maxFrames = 1200 speed = time.Second / 20 + + // drawing buffer length + // + // *2 for extra spaces + // +1 for newlines + bufLen = (width*2 + 1) * height ) var ( @@ -123,7 +129,7 @@ func main() { } // create a drawing buffer - buf := make([]rune, 0, width*height) + buf := make([]rune, 0, bufLen) // clear the screen once screen.Clear() diff --git a/18-project-bouncing-ball/exercises/01-width-and-height/solution/main.go b/18-project-bouncing-ball/exercises/02-width-and-height/solution/main.go similarity index 93% rename from 18-project-bouncing-ball/exercises/01-width-and-height/solution/main.go rename to 18-project-bouncing-ball/exercises/02-width-and-height/solution/main.go index 475049d..793eb65 100644 --- a/18-project-bouncing-ball/exercises/01-width-and-height/solution/main.go +++ b/18-project-bouncing-ball/exercises/02-width-and-height/solution/main.go @@ -57,8 +57,13 @@ func main() { board[column] = make([]bool, height) } + // drawing buffer length + // *2 for extra spaces + // +1 for newlines + bufLen := (width*2 + 1) * height + // create a drawing buffer - buf := make([]rune, 0, width*height) + buf := make([]rune, 0, bufLen) // clear the screen once screen.Clear() diff --git a/18-project-bouncing-ball/exercises/02-previous-positions/main.go b/18-project-bouncing-ball/exercises/03-previous-positions/main.go similarity index 94% rename from 18-project-bouncing-ball/exercises/02-previous-positions/main.go rename to 18-project-bouncing-ball/exercises/03-previous-positions/main.go index 810e48d..7a5fed1 100644 --- a/18-project-bouncing-ball/exercises/02-previous-positions/main.go +++ b/18-project-bouncing-ball/exercises/03-previous-positions/main.go @@ -72,8 +72,13 @@ func main() { board[column] = make([]bool, height) } + // drawing buffer length + // *2 for extra spaces + // +1 for newlines + bufLen := (width*2 + 1) * height + // create a drawing buffer - buf := make([]rune, 0, width*height) + buf := make([]rune, 0, bufLen) // clear the screen once screen.Clear() diff --git a/18-project-bouncing-ball/exercises/02-previous-positions/solution/main.go b/18-project-bouncing-ball/exercises/03-previous-positions/solution/main.go similarity index 82% rename from 18-project-bouncing-ball/exercises/02-previous-positions/solution/main.go rename to 18-project-bouncing-ball/exercises/03-previous-positions/solution/main.go index 456ae4c..06f435d 100644 --- a/18-project-bouncing-ball/exercises/02-previous-positions/solution/main.go +++ b/18-project-bouncing-ball/exercises/03-previous-positions/solution/main.go @@ -23,13 +23,14 @@ func main() { maxFrames = 1200 speed = time.Second / 20 - initVx, initVy = 5, 2 + // initial velocities + ivx, ivy = 5, 2 ) var ( - px, py int // ball position - ppx, ppy int // previous ball position - vx, vy = initVx, initVy // velocities + px, py int // ball position + ppx, ppy int // previous ball position + vx, vy = ivx, ivx // velocities cell rune // current cell (for caching) ) @@ -50,8 +51,13 @@ func main() { board[column] = make([]bool, height) } + // drawing buffer length + // *2 for extra spaces + // +1 for newlines + bufLen := (width*2 + 1) * height + // create a drawing buffer - buf := make([]rune, 0, width*height) + buf := make([]rune, 0, bufLen) // clear the screen once screen.Clear() @@ -62,10 +68,10 @@ func main() { py += vy // when the ball hits a border reverse its direction - if px <= 0 || px >= width-initVx { + if px <= 0 || px >= width-ivx { vx *= -1 } - if py <= 0 || py >= height-initVy { + if py <= 0 || py >= height-ivx { vy *= -1 } diff --git a/18-project-bouncing-ball/exercises/03-single-dimensional/main.go b/18-project-bouncing-ball/exercises/04-single-dimensional/main.go similarity index 86% rename from 18-project-bouncing-ball/exercises/03-single-dimensional/main.go rename to 18-project-bouncing-ball/exercises/04-single-dimensional/main.go index abc900e..0008517 100644 --- a/18-project-bouncing-ball/exercises/03-single-dimensional/main.go +++ b/18-project-bouncing-ball/exercises/04-single-dimensional/main.go @@ -43,13 +43,14 @@ func main() { maxFrames = 1200 speed = time.Second / 20 - initVx, initVy = 5, 2 + // initial velocities + ivx, ivy = 5, 2 ) var ( - px, py int // ball position - ppx, ppy int // previous ball position - vx, vy = initVx, initVy // velocities + px, py int // ball position + ppx, ppy int // previous ball position + vx, vy = ivx, ivy // velocities cell rune // current cell (for caching) ) @@ -70,8 +71,13 @@ func main() { board[column] = make([]bool, height) } + // drawing buffer length + // *2 for extra spaces + // +1 for newlines + bufLen := (width*2 + 1) * height + // create a drawing buffer - buf := make([]rune, 0, width*height) + buf := make([]rune, 0, bufLen) // clear the screen once screen.Clear() @@ -82,10 +88,10 @@ func main() { py += vy // when the ball hits a border reverse its direction - if px <= 0 || px >= width-initVx { + if px <= 0 || px >= width-ivx { vx *= -1 } - if py <= 0 || py >= height-initVy { + if py <= 0 || py >= height-ivy { vy *= -1 } diff --git a/18-project-bouncing-ball/exercises/03-single-dimensional/solution/main.go b/18-project-bouncing-ball/exercises/04-single-dimensional/solution/main.go similarity index 71% rename from 18-project-bouncing-ball/exercises/03-single-dimensional/solution/main.go rename to 18-project-bouncing-ball/exercises/04-single-dimensional/solution/main.go index 67052d0..49c69e2 100644 --- a/18-project-bouncing-ball/exercises/03-single-dimensional/solution/main.go +++ b/18-project-bouncing-ball/exercises/04-single-dimensional/solution/main.go @@ -23,13 +23,14 @@ func main() { maxFrames = 1200 speed = time.Second / 20 - initVx, initVy = 5, 2 + // initial velocities + ivx, ivy = 5, 2 ) var ( - px, py int // ball position - ppx, ppy int // previous ball position - vx, vy = initVx, initVy // velocities + px, py int // ball position + ppx, ppy int // previous ball position + vx, vy = ivx, ivy // velocities cell rune // current cell (for caching) ) @@ -47,8 +48,13 @@ func main() { // create a single-dimensional board board := make([]bool, width*height) + // drawing buffer length + // *2 for extra spaces + // +1 for newlines + bufLen := (width*2 + 1) * height + // create a drawing buffer - buf := make([]rune, 0, width*height) + buf := make([]rune, 0, bufLen) // clear the screen once screen.Clear() @@ -59,25 +65,22 @@ func main() { py += vy // when the ball hits a border reverse its direction - if px <= 0 || px >= width-initVx { + if px <= 0 || px >= width-ivx { vx *= -1 } - if py <= 0 || py >= height-initVy { + if py <= 0 || py >= height-ivy { vy *= -1 } - // check whether the ball goes beyond the borders - if px < width && py < height { - // calculate the new and the previous ball positions - pos := py*width + px - ppos := ppy*width + ppx + // calculate the new and the previous ball positions + pos := py*width + px + ppos := ppy*width + ppx - // remove the previous ball and put the new ball - board[pos], board[ppos] = true, false + // remove the previous ball and put the new ball + board[pos], board[ppos] = true, false - // save the previous positions - ppx, ppy = px, py - } + // save the previous positions + ppx, ppy = px, py // rewind the buffer (allow appending from the beginning) buf = buf[:0]