April 30, 2020 ( last updated : May 01, 2020 )
Python
curses
https://github.com/cao-weiwei/
After knowing the building blocks of curses
, let’s jump onto our first version of the snake game🧐.
Maybe you will think that it seems too abstract for you to take actions to build such a game using the previous knowledge, and the scenarios might be familar with you, if someone told you how to draw a panda in 4 steps 🤨
Exactly right, even we know all the ways how to use tools we cannot build a house without enough preparations ahead. Let’s recall the last time you played the snake game, if you have no ideas about the game, just googling it😏. Here are the major factors in this game:
Except for the above objects, we should know how the ways that users interacting with the game. In this terminal game, we assume that the user can only use four arrow keys to control the moving directions of the snake.
As long as we have the ideas of the game, we could get started on the code, doing the coolest things😎. However, before we dive into the code, it’s best to take a bird’s-eye view and see everything all right:
curses
;First and the formost is to initialize a screen, otherwise nothing will be shown😂.
import curses, random
# 0. initialize a main screen of the game
main_scr = curses.initscr()
curses.curs_set(0) # 0.1 setting the visibility of cursor, 0-invisible, 1-normal, 2-strong
# 1. based on the main screen to create a gaming board
height, width = main_scr.getmaxyx() # 1.1 get the height and width of the main screen
board = curses.newwin(height, width, 0, 0) # 1.2 create a board for gaming
board.keypad(1) # 1.3 using keyboard for receiving commands
board.timeout(100) # 1.4 setting for inerval, every 100 ms the board will get a char from user
When we have the canvas, we can paint snake and food on it right now.
Everything displayed on screen is tracked by using a pair of coordinate, let’s say (y, x)
. Y-asixs represents the height of the object and x-asixs represents the width of the object. If we draw a box on a screen and its coordinate is (y, x)
, it can be explained using below figure.
# 2. draw a snake on the board
snake_y = int(height / 4) # 2.1 initial head coordinates of a snake
snake_x = int(width / 2)
snake = [ # 2.2 draw a snake with coordinates on the board
[snake_y, snake_x], # 2.3 the coordinates of head
[snake_y, snake_x - 1], # 2.4 the coordinates of body
[snake_y, snake_x - 2],
[snake_y, snake_x - 3],
[snake_y, snake_x - 4]
]
board.addch(snake[0][0], snake[0][1], '+') # 2.5 paint chars on the screen and update screen
main_scr.refresh()
# 3. put the first food spot on the board
food_y = int(height / 2) # 3.1 initial position of food
food_x = int(width / 2)
food_pos = [food_y, food_x]
board.addch(food_pos[0], food_pos[1], '$') # 3.2 paint the first position of food
main_scr.refresh()
The next is the core of the game, which will contrl the snake to move on the board and eat the food. Before that we should set a defualt direction of the snake, then it will automatically move at first.
# 4. set the default direction of the snake
key = curses.KEY_RIGHT
In curses
, we use the function window.getch()
to get the pressed key from keyboard and it will return an integer which represents a key. Keys are referred to by integer constants with names starting with KEY_
# 6. get command from user to control the snake
next_key = board.getch() # 6.1 waiting for getting input from keyboard
if next_key != -1: # 6.2 successfully received from keyboard
if key == curses.KEY_RIGHT and next_key != curses.KEY_LEFT \
or key == curses.KEY_LEFT and next_key != curses.KEY_RIGHT \
or key == curses.KEY_UP and next_key != curses.KEY_DOWN \
or key == curses.KEY_DOWN and next_key != curses.KEY_UP:
key = next_key
After moving the directions of the snake, we should check the status of the snake to ensure the snake is alive and the game can continue. There are two cases of ending game, one is the snake meets the boundary of the board, and the other is the snake crash itself.
# 7. check whether the snake is alive
if snake[0][0] in [0, height] or snake[0][1] in [0, width] or snake[0] in snake[1:]: # 7.1 cases for ending game
main_scr.keypad(0) # reset the terminal
curses.echo()
curses.nocbreak()
curses.endwin() # close the terminal
quit()
# 8. draw a new head of the snake and concatenate it into the previous snake body
snake_y = snake[0][0]
snake_x = snake[0][1]
if key == curses.KEY_RIGHT: # move to right
snake_x += 1
elif key == curses.KEY_LEFT: # move to left
snake_x -= 1
elif key == curses.KEY_UP: # move to up
snake_y -= 1
elif key == curses.KEY_DOWN: # move to down
snake_y += 1
snake.insert(0, [snake_y, snake_x]) # put the new head of snake in the list
When the snake moved, the food might be eaten by the snake or not. If the snake eats the food, we should lengthen the snake and put another food on the screen, otherwise we don’t change anything on the screen.
# 9. check whether the food is eaten by the snake
if snake[0] == food_pos: # 9.1 eat the food
food_pos = None
while not food_pos: # create new food randomly but excluding the coordinates in snake
food_y = random.randint(1, height - 1)
food_x = random.randint(1, width - 1)
food_pos = [food_y, food_x]
if food_pos not in snake: # avoid new coordinates in snake
board.addch(food_pos[0], food_pos[1], '$')
else:
food_pos = None
else: # 9.2 not eat the food, pop the tail since we insert a new head before
tail = snake.pop()
board.addch(tail[0], tail[1], ' ')
Don’t forget to paint changes on the screen and update it.
# 10. draw the new head on screen
board.addch(snake[0][0], snake[0][1], '+')
main_scr.refresh()
Once we achieve the functionalities of above sections in #3.1 - #3.3, we should make the snake alived on the screen, but how? The code is a little tricky and straightforward, we need to put the code in a infinite loop and boom all things have done😎.
# 5. Main loop until the user lose or close the game.
while True:
# code in 3.1 - 3.3
Finally, we achieved the first version of the game, enjoy it 🤩!
See previous articles plece check 👉here👈. Next, we’ll improve our tiny game using GUI, however, before that we should go deep in analysis using object oriented programming techniques.
If you like my articles please give me a star or leave comments below, thanks!
Originally published April 30, 2020
Latest update May 01, 2020
Related posts :