// Snake game
package main
import (
"fmt"
"math/rand"
"time"
"github.com/eiannone/keyboard"
"strconv"
)
type Snake struct {
head [2]int
body []([2]int)
direction rune
live bool
}
func (snake *Snake) turn(d rune) {
switch d {
case 'u':
switch snake.direction {
case 'l':
snake.direction = 'u'
case 'r':
snake.direction = 'u'
}
case 'l':
switch snake.direction {
case 'u':
snake.direction = 'l'
case 'd':
snake.direction = 'l'
}
case 'r':
switch snake.direction {
case 'u':
snake.direction = 'r'
case 'd':
snake.direction = 'r'
}
case 'd':
switch snake.direction {
case 'r':
snake.direction = 'd'
case 'l':
snake.direction = 'd'
}
}
}
func (snake *Snake) update() {
old_pos := [...]int{snake.head[0], snake.head[1]}
switch snake.direction {
case 'u':
snake.head[0] -= 1
case 'l':
snake.head[1] -= 1
case 'd':
snake.head[0] += 1
case 'r':
snake.head[1] += 1
}
for i,_ := range snake.body {
snake.body[i][0], old_pos[0] = old_pos[0], snake.body[i][0]
snake.body[i][1], old_pos[1] = old_pos[1], snake.body[i][1]
}
if snake.head[0] == food_i && snake.head[1] == food_j {
snake.body = append(snake.body, old_pos)
}
if snake.head[0] == 0 || snake.head[1] == 0 || snake.head[0] == board_h - 1 || snake.head[1] == board_w - 1 {
snake.die()
}
}
func (snake *Snake) die() {
snake.live = false
}
func (snake Snake) draw(board [][]rune) {
// clearnig board
for i:=0;i<board_h;i++ {
for j:=0;j<board_w;j++ {
if board[i][j] == '%' {
continue
}
if i == 0 || j == 0 || i == board_h - 1 || j == board_w - 1 {
board[i][j] = '#'
} else {
board[i][j] = ' '
}
}
}
// snake head
board[snake.head[0]][snake.head[1]] = '@'
// snake body
for _, b := range snake.body {
board[b[0]][b[1]] = '*'
}
}
func print_board(board [][]rune) {
for _, l := range board {
for _, c := range l {
fmt.Printf("%c", c)
}
fmt.Printf("\n")
}
}
func add_food(board [][]rune) {
food_i = rand.Intn(board_h-1)+1
food_j = rand.Intn(board_w-1)+1
if board[food_i][food_j] == ' ' {
board[food_i][food_j] = '%'
} else {
add_food(board)
}
}
func food_eaten(board [][]rune) bool {
return board[food_i][food_j] != '%'
}
func input_loop(snake *Snake) {
err := keyboard.Open()
if err != nil {
fmt.Println("Let me guess, windows?")
fmt.Println("Sorry but I only test it on Linux")
snake.die()
}
defer keyboard.Close()
for ;snake.live; {
_, key, err := keyboard.GetKey()
if err != nil {
continue
}
defer keyboard.Close() // reset the terminal settings
// still don't know why it messed up
switch key {
case keyboard.KeyArrowUp:
snake.turn('u')
case keyboard.KeyArrowDown:
snake.turn('d')
case keyboard.KeyArrowLeft:
snake.turn('l')
case keyboard.KeyArrowRight:
snake.turn('r')
case keyboard.KeyEsc:
snake.die()
}
time.Sleep(10 * time.Millisecond)
}
}
// Constants
const es_clear = "\033[H\033[2J"
const es_BG_white = "\033[47m"
const es_reset = "\033[0m"
const board_w = 80
const board_h = 24
// Globals
var food_i int = rand.Intn(board_h-1)+1
var food_j int = rand.Intn(board_w-1)+1
func main() {
board := make([][]rune, board_h)
for i := range board {
board[i] = make([]rune, board_w)
}
var snake Snake
snake.head[0] = board_h / 2
snake.head[1] = board_w / 2
snake.direction = 'r'
snake.live = true
go input_loop(&snake)
for ;snake.live; {
snake.update()
snake.draw(board)
if food_eaten(board) {
add_food(board)
}
fmt.Print(es_clear)
print_board(board)
time.Sleep(100 * time.Millisecond)
}
// end screen
score := len(snake.body)
score_string := "| Your Score is " + strconv.Itoa(score) + " |"
cf := 0
for ;cf<board_h+board_w-1;cf++ {
for i:=0;i<board_h;i++ {
for j:=0;j<board_w;j++ {
if i + j == cf {
board[i][j] = '+'
}
}
}
fmt.Print(es_clear)
print_board(board)
time.Sleep(100 * time.Millisecond)
}
i := board_h / 2
j := (board_w / 2) - (len(score_string) / 2)
for index, v := range score_string {
board[i-1][j+index] = '-'
board[i][j+index] = v
board[i+1][j+index] = '-'
}
fmt.Print(es_clear)
print_board(board)
}