add: new exercises to bouncing ball

This commit is contained in:
Inanc Gumus
2019-03-22 20:42:42 +03:00
parent b0efd28975
commit 4021e83ab2
3 changed files with 205 additions and 5 deletions

View File

@ -0,0 +1,110 @@
// 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"
"github.com/mattn/go-runewidth"
)
// ---------------------------------------------------------
// EXERCISE: No Slice
//
// Can you modify the program so that it doesn't use a
// slice for the board. You can use a slice for the buffer
// though.
//
// In this exercise, you'll understand that you don't
// have to use slices in any problem you encounter with.
//
// See what it feels like not using a slice for this
// solution.
//
// Think about why you have to use a slice for the buffer?
//
// Can there be any other solution?
//
// ---------------------------------------------------------
func main() {
const (
cellEmpty = ' '
cellBall = '⚾'
maxFrames = 1200
speed = time.Second / 20
ivx, ivy = 1, 1 // initial velocities
)
var (
px, py int // ball position
ppx, ppy int // previous ball position
vx, vy = ivx, ivy // velocities
cell rune // current cell (for caching)
)
width, height := screen.Size()
width /= runewidth.RuneWidth(cellBall)
height-- // there is a 1 pixel border in my terminal
// REMOVE THIS: create a single-dimensional board
board := make([]bool, width*height)
// create a drawing buffer
// *2 for extra spaces
// +1 for newlines
buf := make([]rune, 0, (width*2+1)*height)
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-ivx {
vx *= -1
}
if py <= 0 || py >= height-ivy {
vy *= -1
}
// remove the previous ball and put the new ball
pos := py*width + px
ppos := ppy*width + ppx
ppx, ppy = px, py
board[pos], board[ppos] = true, false
buf = buf[:0]
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
cell = cellEmpty
if board[y*width+x] {
cell = cellBall
}
buf = append(buf, cell, ' ')
}
buf = append(buf, '\n')
}
screen.MoveTopLeft()
fmt.Print(string(buf))
time.Sleep(speed)
}
}

View File

@ -0,0 +1,81 @@
// 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"
"github.com/mattn/go-runewidth"
)
func main() {
const (
cellEmpty = ' '
cellBall = '⚾'
maxFrames = 1200
speed = time.Second / 20
// initial velocities
ivx, ivy = 1, 1
)
var (
px, py int // ball position
vx, vy = ivx, ivy // velocities
cell rune // current cell (for caching)
)
width, height := screen.Size()
width /= runewidth.RuneWidth(cellBall)
height-- // there is a 1 pixel border in my terminal
// create a drawing buffer
// *2 for extra spaces
// +1 for newlines
buf := make([]rune, 0, (width*2+1)*height)
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
}
buf = buf[:0]
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
cell = cellEmpty
if px == x && py == y {
cell = cellBall
}
buf = append(buf, cell, ' ')
}
buf = append(buf, '\n')
}
screen.MoveTopLeft()
fmt.Print(string(buf))
time.Sleep(speed)
}
}

View File

@ -1,13 +1,22 @@
# Exercises # Bouncing Ball Exercises
1. **[Adjust the width and height automatically](https://github.com/inancgumus/learngo/tree/master/18-project-bouncing-ball/exercises/01-width-and-height)** 1. **[Find the Bug](https://github.com/inancgumus/learngo/tree/master/18-project-bouncing-ball/exercises/01-find-the-bug)**
There is a bug in the bouncing ball code. Test yourself that you really understand how the backing arrays work.
2. **[Adjust the width and height automatically](https://github.com/inancgumus/learngo/tree/master/18-project-bouncing-ball/exercises/02-width-and-height)**
In this exercise, your goal is getting the width and height of the terminal screen from your operating system (instead of setting the width and height manually). In this exercise, your goal is getting the width and height of the terminal screen from your operating system (instead of setting the width and height manually).
2. **[Previous positions](https://github.com/inancgumus/learngo/tree/master/18-project-bouncing-ball/exercises/02-previous-positions)** 3. **[Previous positions](https://github.com/inancgumus/learngo/tree/master/18-project-bouncing-ball/exercises/03-previous-positions)**
Let's optimize the program once more. This time you're going to optimize the clearing off the previous positions. Let's optimize the program once more. This time you're going to optimize the clearing off the previous positions.
3. **[Use a single dimensional slice](https://github.com/inancgumus/learngo/tree/master/18-project-bouncing-ball/exercises/03-single-dimensional)** 4. **[Use a single dimensional slice](https://github.com/inancgumus/learngo/tree/master/18-project-bouncing-ball/exercises/04-single-dimensional)**
For the board slice, instead of using a multi-dimensional slice, let's use a single-dimensional slice. In this exercise, you'll understand and deeply internalize why I've used a multi-dimensional board slice. For the board slice, instead of using a multi-dimensional slice, let's use a single-dimensional slice. In this exercise, you'll understand and deeply internalize why I've used a multi-dimensional board slice.
5. **[Don't use a slice for the board](https://github.com/inancgumus/learngo/tree/master/18-project-bouncing-ball/exercises/05-no-slice)**
Expand your horizon: Don't use a slice for the board. You only need a slice for the buffer, only that.