code

#!/usr/bin/env python
"""
file snake.py, run: python snake.py
Written by Jason Zhao at 2016/1/10.
"""

from __future__ import print_function
import sys, time, termios, random, select

# define global vars
# map size (40+28)x20
width, high, info= 41, 21, 28
body = [(width//2, 1)]
dir_x, dir_y = 0, 1
ch_snake, ch_wall, ch_food, key = 'X', '#', '@', '-'
food = [[False for fd_y in range(high + 1)] for fd_x in range(width + 1)]
pnt_interval, key_interval, food_ct = 0.2, 0.01, 0

# define functions
# x and y start from 1
def goto_xy(x, y):
    print('\033[%s;%sH' % (y, x), end='', sep='')

# draw map's edge, the wall and info display box    
def draw_edge():
    print('\033[2J\033[?25l')
    for x in range(high):
        goto_xy(width, x)
        print(ch_wall, end='', sep='')
        goto_xy(width + info, x)
        print(ch_wall, end='', sep='')
    goto_xy(0, high)
    print(ch_wall * (width + info))

def draw_snake():
    for pos in body:
        goto_xy(pos[0], pos[1])
        print(ch_snake, end='', sep='')

def get_keys():
    global key
    fd = sys.stdin.fileno()
    old = termios.tcgetattr(fd)
    new = termios.tcgetattr(fd)
    # turn off echo and enter
    new[3] = new[3] & ~termios.ECHO & ~termios.ICANON
    count, times = 0, pnt_interval//key_interval
    try:
        termios.tcsetattr(fd, termios.TCSADRAIN, new)
        while count < times:
            # sleep time second
            time.sleep(key_interval)
            # support non-blocking input
            if select.select([sys.stdin], [], [], 0) == ([sys.stdin], [], []):
                key = sys.stdin.read(1)
                if key == 'p': break
            count += 1
    except KeyboardInterrupt:
        print('get: ctrl-c')
        exit()
    finally:
        termios.tcsetattr(fd, termios.TCSADRAIN, old)

def move_snake():
    global food_ct
    new_x, new_y = body[-1][0] + dir_x, body[-1][1] + dir_y
    # snake can't turn around
    if len(body) > 1 and (new_x, new_y) == body[-2]:
        new_x, new_y = body[-1][0] - dir_x, body[-1][1] - dir_y
    if food[new_x][new_y]:
        body.append((new_x, new_y))
        food[new_x][new_y] = False
        food_ct += 1
        return True
    else:
        body.append((new_x, new_y))
        tail_x, tail_y = body.pop(0)
        goto_xy(tail_x, tail_y)
        # cut the tail of snake
        print(' ', end='', sep='')
        return False

def make_food(pre_food=False, first_run=False):
    def mk_food():
        while True:
            food_x = random.randrange(1, width)
            food_y = random.randrange(1, high)
            # food can't appear on body of snake
            if not (food_x, food_y) in body:
                food[food_x][food_y] = True
                goto_xy(food_x, food_y)
                print(ch_food, end='', sep='')
                break
    if first_run:
        mk_food()
    elif pre_food:
        mk_food()

def get_dir():
    global dir_x, dir_y
    if key == 'w':
        dir_x, dir_y = 0, -1
    elif key == 's':
        dir_x, dir_y = 0, +1
    elif key == 'a':
        dir_x, dir_y = -1, 0
    elif key == 'd':
        dir_x, dir_y = +1, 0

def detect_pos():
    x, y = body[-1][0], body[-1][1]
    if (x > 0 and x < width) and (y > 0 and y < high) and (not (x, y) in body[:-1]):
        return True
    else:
        return False

def print_info(info='', flag=True):
    if flag:
        goto_xy(width + 2, 4)
        print('[w/s/a/d] to move')
        goto_xy(width + 2, 5)
        print('[p] to quit')
        goto_xy(width + 2, 7)
        print('score:', food_ct)
        goto_xy(width + 2, 9)
        print('length of snake:', len(body))
        goto_xy(width + 2, 11)
        print('get:', key)
    else:
        print('\033[2J')
        goto_xy(0, 0)
        print('#' * 13)
        print('# %s #' % info)
        print('#' * 13)

def main_loop():
    pre_food = False
    first_run = True
    draw_edge()
    print_info(flag=True)
    while key != 'p':
        make_food(pre_food, first_run)
        pre_food = move_snake()
        first_run = False
        # snake hits the wall or itself, exit
        if not detect_pos():
            print_info('GAME OVER', flag=False)
            exit()
        draw_snake()
        print_info(flag=True)
        #time.sleep(pnt_interval)
        get_keys()
        get_dir()        
    else:
        print_info('GAME EXIT', flag=False)
        exit()

# self-test or be a  module
if __name__ == '__main__':
    main_loop()

run

$ python snake.py

说明:文章若有不足、错误之处欢迎各位指正。

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐