From aea82ab765e7cda8e59409296b31ee60783d6825 Mon Sep 17 00:00:00 2001 From: Sacha Ligthert Date: Thu, 23 Nov 2023 22:36:44 +0100 Subject: [PATCH] #4 Gives the snake a tail. --- apple.go | 12 ++++--- game.go | 36 +++++++++++---------- main.go | 9 ------ render.go | 6 ++-- snake.go | 95 +++++++++++++++++++++++++++++++++++++++++++++++++++---- types.go | 15 +++++++++ 6 files changed, 133 insertions(+), 40 deletions(-) create mode 100644 types.go diff --git a/apple.go b/apple.go index 8b5e860..691655a 100644 --- a/apple.go +++ b/apple.go @@ -15,7 +15,8 @@ import ( // return foodsRune[randomIndex] // } -func placeApple(snakex *int, snakey *int) Apple { +// func placeApple(snakex int, snakey int) Apple { +func placeApple(snake *Snake) Apple { var x, y int var found bool @@ -24,12 +25,15 @@ func placeApple(snakex *int, snakey *int) Apple { x = rand.Intn(80) y = rand.Intn(24) - if x != *snakex && y != *snakey { + if x != snake.head.x && y != snake.head.y { found = true } if x == 0 || x == 79 || y == 0 || y == 23 { found = false } + if hitsTail(snake, x, y) { + found = false + } } @@ -42,6 +46,6 @@ func placeApple(snakex *int, snakey *int) Apple { } -func drawApple(screen tcell.Screen, style tcell.Style, x int, y int) { - screen.SetContent(x, y, '🍎', nil, style) +func drawApple(screen tcell.Screen, style tcell.Style, apple *Apple) { + screen.SetContent(apple.x, apple.y, 'o', nil, style) } diff --git a/game.go b/game.go index f547eca..d8fe3a3 100644 --- a/game.go +++ b/game.go @@ -45,12 +45,6 @@ func gameDirector(screen tcell.Screen, style tcell.Style, keypresses chan int, g var score int = 0 var scoreCounter int = 1 - //var field [80][24]int - // fill up the field: - // 0: empty - // 1: snake - // 2: apple - // 3: border // Board size var screenx = 80 @@ -63,30 +57,38 @@ func gameDirector(screen tcell.Screen, style tcell.Style, keypresses chan int, g // Last direction we went in var lastpress int = 1 - var apple Apple = placeApple(&snakex, &snakey) + var snake Snake = initSnake(&snakex, &snakey) + var apple Apple = placeApple(&snake) for { // Take input or sleep select { case press := <-keypresses: - snakeDirection(press, &snakex, &snakey) + snakeDirection(press, &snake) lastpress = press case <-time.After(500 * time.Millisecond): - snakeDirection(lastpress, &snakex, &snakey) + snakeDirection(lastpress, &snake) } - if snakex == apple.x && snakey == apple.y { - apple = placeApple(&snakex, &snakey) + if snake.head.x == apple.x && snake.head.y == apple.y { + apple = placeApple(&snake) score += scoreCounter scoreCounter++ + snake.length = 3 + score } // Call it quits once the snake hits the border. - if snakex == 0 || snakex == screenx-1 { + if snake.head.x == 0 || snake.head.x == screenx-1 { close(gamestate) return - } else if snakey == 0 || snakey == screeny-1 { + } else if snake.head.y == 0 || snake.head.y == screeny-1 { + close(gamestate) + return + } + + // Check if head intersects with any parts of the body + if hitsTail(&snake, snake.head.x, snake.head.y) { close(gamestate) return } @@ -95,10 +97,10 @@ func gameDirector(screen tcell.Screen, style tcell.Style, keypresses chan int, g screen.Clear() // Draw the screen - drawBox(screen, 0, 0, screenx-1, screeny-1, style) - drawCoords(screen, style, &snakex, &snakey) - drawApple(screen, style, apple.x, apple.y) - drawSnake(screen, style, snakex, snakey) + drawBox(screen, style, 0, 0, screenx-1, screeny-1) + drawCoords(screen, style, &snake) + drawApple(screen, style, &apple) + drawSnake(screen, style, &snake) drawScore(screen, style, score) // Draw the screen diff --git a/main.go b/main.go index 39d10c6..e5273d0 100644 --- a/main.go +++ b/main.go @@ -4,15 +4,6 @@ import ( "log" ) -type Position struct { - x int - y int -} - -type Apple Position - -//type Snake Position - func main() { // Create channles to manage keypresses and the gamestate diff --git a/render.go b/render.go index 358b51f..1cb82c8 100644 --- a/render.go +++ b/render.go @@ -26,15 +26,15 @@ func drawScore(screen tcell.Screen, style tcell.Style, score int) { } } -func drawCoords(screen tcell.Screen, style tcell.Style, snakex *int, snakey *int) { +func drawCoords(screen tcell.Screen, style tcell.Style, snake *Snake) { var x, y int = 25, 24 - for _, r := range []rune("[ x:" + strconv.FormatInt(int64(*snakex), 10) + " y: " + strconv.FormatInt(int64(*snakey), 10) + " ]") { + for _, r := range []rune("[ x:" + strconv.FormatInt(int64(*&snake.head.x), 10) + " y: " + strconv.FormatInt(int64(*&snake.head.y), 10) + " ]") { screen.SetContent(x, y-1, r, nil, style) x++ } } -func drawBox(s tcell.Screen, x1, y1, x2, y2 int, style tcell.Style) { +func drawBox(s tcell.Screen, style tcell.Style, x1, y1, x2, y2 int) { if y2 < y1 { y1, y2 = y2, y1 } diff --git a/snake.go b/snake.go index a2d9251..6224c22 100644 --- a/snake.go +++ b/snake.go @@ -4,18 +4,99 @@ import ( "github.com/gdamore/tcell/v2" ) -func drawSnake(screen tcell.Screen, style tcell.Style, x int, y int) { - screen.SetContent(x, y, '🐍', nil, style) +func initSnake(snakex *int, snakey *int) Snake { + var x, y int = *snakex, *snakey + snake := Snake{ + head: Position{ + x: x, + y: y, + }, + tail: []Position{ + { + x: x - 1, + y: y, + }, + { + x: x - 2, + y: y, + }, + { + x: x - 3, + y: y, + }, + }, + length: 3, + direction: 1, + } + + return snake } -func snakeDirection(press int, snakex *int, snakey *int) { +func drawSnake(screen tcell.Screen, style tcell.Style, snake *Snake) { + + // Reverse tail, chop of the excesses, + snake.tail = ReverseSlice(snake.tail) + if len(snake.tail) > snake.length { + snake.tail = snake.tail[:snake.length] + } + // reverse it back to the original order, replace the tail in `snake` + snake.tail = ReverseSlice(snake.tail) + + // Draw the body + for _, segment := range snake.tail { + screen.SetContent(segment.x, segment.y, '+', nil, style) + } + + // Draw the head, make sure it is on top of everything + screen.SetContent(snake.head.x, snake.head.y, '0', nil, style) + +} + +func snakeDirection(press int, snake *Snake) { if press == Left { - *snakex-- + if snake.direction != Right { + snake.head.x-- + snake.tail = append(snake.tail, Position{x: snake.head.x + 1, y: snake.head.y}) + snake.direction = press + } } else if press == Right { - *snakex++ + if snake.direction != Left { + snake.head.x++ + snake.tail = append(snake.tail, Position{x: snake.head.x - 1, y: snake.head.y}) + snake.direction = press + } } else if press == Up { - *snakey-- + if snake.direction != Down { + snake.head.y-- + snake.tail = append(snake.tail, Position{x: snake.head.x, y: snake.head.y + 1}) + snake.direction = press + } } else if press == Down { - *snakey++ + if snake.direction != Up { + snake.head.y++ + snake.tail = append(snake.tail, Position{x: snake.head.x, y: snake.head.y - 1}) + snake.direction = press + } } } + +// Check if a pos hits the tail +func hitsTail(snake *Snake, x int, y int) bool { + var hit bool = false + + for _, segment := range snake.tail { + if segment.x == x && segment.y == y { + hit = true + } + } + + return hit +} + +func ReverseSlice[T comparable](s []T) []T { + var r []T + for i := len(s) - 1; i >= 0; i-- { + r = append(r, s[i]) + } + return r +} diff --git a/types.go b/types.go new file mode 100644 index 0000000..dcedcc7 --- /dev/null +++ b/types.go @@ -0,0 +1,15 @@ +package main + +type Position struct { + x int + y int +} + +type Apple Position + +type Snake struct { + head Position + tail []Position + length int + direction int +}