#!/usr/bin/env python#coding:utf8#author:Z time:2018/8/27
"""Simple Snake console game for Python 3.
From https://github.com/borisuvarov/cursed_snake
Use it as introduction to curses module.
Warning: curses module available only in Unix.
On Windows use UniCurses (https://pypi.python.org/pypi/UniCurses).
UniCurses is not installed by default."""
import curses #https://docs.python.org/3/library/curses.html
importtimeimportrandomdef redraw(): #Redraws game field and it's content after every turn
#win.erase()
win.clear()
draw_food()#Draws food on the game field
draw_snake() #Draws snake
draw_menu()
win.refresh()defdraw_menu():
win.addstr(0,0,"Score:" + str(len(snake) - 2) + "Press 'q' to quit", curses.color_pair(5))defdraw_snake():try:
n= 0 #There can be only one head
for pos in snake: #Snake is the list of [y, x], so we swap them below
if n ==0:
win.addstr(pos[1], pos[0], "@", curses.color_pair(ex_foodcolor)) #Draws head
else:
win.addstr(pos[1], pos[0], "#", curses.color_pair(ex_foodcolor)) #Draws segment of the body
n += 1
exceptException as drawingerror:print(drawingerror, str(cols), str(rows))defdraw_food():for pos infood:
win.addstr(pos[1], pos[0], "+", curses.color_pair(foodcolor))defdrop_food():
x= random.randint(1, cols - 2)
y= random.randint(1, rows - 2)for pos in snake: #Do not drop food on snake
if pos ==[x, y]:
drop_food()
food.append([x, y])defmove_snake():global snake #List
global grow_snake #Boolean
global cols, rows #Integers
head= snake[0] #Head is the first element of "snake list"
if not grow_snake: #Remove tail if food was not eaten on this turn
snake.pop()else: #If food was eaten on this turn, we don't pop last item of list,
grow_snake = False #but we restore default state of grow_snake
if direction == DIR_UP: #Calculate the position of the head
head = [head[0], head[1] - 1] #We will swap x and y in draw_snake()
if head[1] ==0:
head[1] = rows - 2 #Snake passes through the border
elif direction ==DIR_DOWN:
head= [head[0], head[1] + 1]if head[1] == rows - 1:
head[1] = 1
elif direction ==DIR_LEFT:
head= [head[0] - 1, head[1]]if head[0] ==0:
head[0]= cols - 2
elif direction ==DIR_RIGHT:
head= [head[0] + 1, head[1]]if head[0] == cols - 1:
head[0]= 1snake.insert(0, head)#Insert new head
defis_food_collision():for pos infood:if pos ==snake[0]:
food.remove(pos)globalfoodcolorglobalex_foodcolor
ex_foodcolor=foodcolor
foodcolor= random.randint(1, 6) #Pick random color of the next food
returnTruereturnFalsedefgame_over():globalis_game_over
is_game_over=True
win.erase()
win.addstr(10, 20, "Game over! Your score is" + str(len(snake)) + "Press 'q' to quit", curses.color_pair(1))def is_suicide(): #If snake collides with itself, game is over
for i in range(1, len(snake)):if snake[i] ==snake[0]:returnTruereturnFalsedefend_game():
curses.nocbreak()
win.keypad(0)
curses.echo()
curses.endwin()#Initialisation starts --------------------------------------------
DIR_UP = 0 #Snake's directions, values are not important,
DIR_RIGHT = 1 #they сan be "a", "b", "c", "d" or something else
DIR_DOWN = 2DIR_LEFT= 3is_game_over=False
grow_snake=False
snake= [[10, 5], [9, 5]] #Set snake size and position
direction =DIR_RIGHT
food=[]
foodcolor= 2ex_foodcolor= 3win= curses.initscr() #Game field in console initialised with curses module
curses.start_color() #Enables colors
curses.init_pair(1, curses.COLOR_CYAN, curses.COLOR_BLACK)
curses.init_pair(2, curses.COLOR_BLUE, curses.COLOR_BLACK)
curses.init_pair(3, curses.COLOR_GREEN, curses.COLOR_BLACK)
curses.init_pair(4, curses.COLOR_MAGENTA, curses.COLOR_BLACK)
curses.init_pair(5, curses.COLOR_RED, curses.COLOR_BLACK)
curses.init_pair(6, curses.COLOR_YELLOW, curses.COLOR_BLACK)
win.keypad(1) #Enable arrow keys
win.nodelay(1) #Do not wait for keypress
curses.curs_set(0) #Hide cursor
curses.cbreak() #Read keys instantaneously
curses.noecho() #Do not print stuff when keys are pressed
rows, cols = win.getmaxyx() #Get terminal window size
#Initialisation ends ---------------------------------------------
#Main loop starts ------------------------------------------------
drop_food()
redraw()whileTrue:if is_game_over isFalse:
redraw()
key= win.getch() #Returns a key, if pressed
time.sleep(0.1) #Speed of the game
if key != -1: #win.getch returns -1 if no key is pressed
if key ==curses.KEY_UP:if direction != DIR_DOWN: #Snake can't go up if she goes down
direction =DIR_UPelif key ==curses.KEY_RIGHT:if direction !=DIR_LEFT:
direction=DIR_RIGHTelif key ==curses.KEY_DOWN:if direction !=DIR_UP:
direction=DIR_DOWNelif key ==curses.KEY_LEFT:if direction !=DIR_RIGHT:
direction=DIR_LEFTelif chr(key) == "q":break
if is_game_over isFalse:
move_snake()ifis_suicide():
game_over()ifis_food_collision():
drop_food()
grow_snake=True
end_game()#Main loop ends --------------------------------------------------