1、主要功能

  1. 自定义食物
  2. 障碍物设置
  3. 游戏难度控制
  4. 游戏记录
  5. AI对战
  6. AI版发射炮弹

2、游戏截图

python 如何识别游戏画面并自动操控 python自动打游戏ai_贪吃蛇

3、游戏代码

1.启动器部分

from tkinter import *
import os, sys
from tkinter import messagebox
import pygame
import ctypes
import tkinter as tk


pygame.init()
root = Tk()
root.title('启动程序')


sw = root.winfo_screenwidth()
sh = root.winfo_screenheight()
ww = 400
wh = 900
x = (sw-ww) / 2
y = (sh-wh) / 2
ctypes.windll.shcore.SetProcessDpiAwareness(1)
ScaleFactor=ctypes.windll.shcore.GetScaleFactorForDevice(0)
root.tk.call('tk', 'scaling', ScaleFactor/75)
root.geometry("%dx%d+%d+%d" %(ww,wh,x,y))



C = Canvas(root, bg='white', height=300, width=400)
filename = PhotoImage(file='x.png')
background_label = Label(root, image=filename)
background_label.place(x=0, y=0, relwidth=1, relheight=0.3)
C.pack()



l1 = Label(root, text="食物数量:1~50")
l1.pack()
xls_text = StringVar()
xls = Entry(root, textvariable = xls_text)
xls_text.set(" ")
xls.pack()



def open_app(app_dir):
    os.startfile(app_dir)


    
def setnum():
    x = xls_text.get()
    if x == ' ':
        x=1
    file_handle1 = open('date2.txt', mode='w')
    file_handle1.write('%d' % int(x))
    file_handle1.close()  



def x():
    app_dir = 'snake.py'
    open_app(app_dir)



def renji():
    app_dir = 'PythonAISnake.py'
    open_app(app_dir)



def date():
    while True:
        f = open('date.txt', 'r')
        str1 = f.read()
        f.close
        return str1


def h():
        window1 = Tk()
        window1.title('游戏记录')
        label = Label(window1, text=date())
        label.pack()
        m8 = Button(window1, text='清空数据', font=('KaiTi', 10, 'bold'), bg='white', fg='black', bd=2, width=10, command=clear_date)        
        m8.pack()
        window1.mainloop()



#open("date.txt",'w').close()
def clear_date():
    x = messagebox.askquestion('提示','确定清除?')
    print(x)
    if x == 'yes' :
        open("date.txt",'w').close()



def m():
    try:
        setnum()
        window2 = Tk()
        window2.title('游戏选项')
        sw = window2.winfo_screenwidth()
        sh = window2.winfo_screenheight()
        ww = 400
        wh = 400
        x = (sw-ww) / 2
        y = (sh-wh) / 2
        window2.geometry("%dx%d+%d+%d" %(ww,wh,x,y))
        m1 = Button(window2, text='简单', font=('KaiTi', 36, 'bold'), bg='white', fg='black', bd=2, width=10, command=(lambda : xf(s=1)))
        m2 = Button(window2, text='中等', font=('KaiTi', 36, 'bold'), bg='white', fg='black', bd=2, width=10, command=(lambda : xf(s=2)))
        m3 = Button(window2, text='困难', font=('KaiTi', 36, 'bold'), bg='white', fg='black', bd=2, width=10, command=(lambda : xf(s=3)))
        m1.pack()
        m2.pack()
        m3.pack()
        window2.mainloop()
    except ValueError:
        messagebox.showinfo("提示","请输入整数")



def xf(s):
    if s == 1:
        x = 5
    else:
        if s == 2:
            x = 10
        else:
            x = 15
    file_handle = open('date1.txt', mode='w')
    file_handle.write('%s' % str(x))
    file_handle.close()
    app_dir = 'snake.py'
    open_app(app_dir)



b = Button(root, text='开始游戏', font=('KaiTi', 36, 'bold'), bg='white', fg='black', bd=2, width=10, command=m)
c = Button(root, text='退出游戏', font=('KaiTi', 36, 'bold'), bg='white', fg='black', bd=2, width=10, command=(root.quit))
d = Button(root, text='游戏记录', font=('KaiTi', 36, 'bold'), bg='white', fg='black', bd=2, width=10, command=h)
k = Button(root, text='人机对战', font=('KaiTi', 36, 'bold'), bg='white', fg='black', bd=2, width=10, command=renji)
b.pack()
c.pack()
d.pack()
k.pack()
root.mainloop()

 2.普通版部分

## 导入相关模块
import random
import pygame
import sys
import time

from pygame.locals import *


snake_speed = 15 #贪吃蛇的速度
number = 11
f = open('date1.txt', 'r')
str1 = f.read()
f.close
snake_speed = int(str1)#通过读取date1.txt文件中的数据实现游戏难度的控制
fl = open('date2.txt','r')
str2 = fl.read()
fl.close
if str2 == '':
        str2 = 1
number =int(str2)
if (number < 1 or number > 50):
        number = 1


windows_width = 800
windows_height = 600 #游戏窗口的大小
cell_size = 20       #贪吃蛇身体方块大小,注意身体大小必须能被窗口长宽整除

''' #初始化区
由于我们的贪吃蛇是有大小尺寸的, 因此地图的实际尺寸是相对于贪吃蛇的大小尺寸而言的
'''
map_width = int(windows_width / cell_size)
map_height = int(windows_height / cell_size)

# 颜色定义
white = (255, 255, 255)
black = (0, 0, 0)
gray = (230, 230, 230)
dark_gray = (40, 40, 40)
DARKGreen = (0, 155, 0)
Green = (0, 255, 0)
Red = (255, 0, 0)
blue = (0, 0, 255)
dark_blue =(0,0, 139)
champagne = (255,255,153)


BG_COLOR = white #游戏背景颜色
pygame.mixer.init()
music = pygame.mixer.Sound("2.wav")

# 定义方向
UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4

HEAD = 0 #贪吃蛇头部下标

#主函数
def main():
	pygame.init()
	snake_speed_clock = pygame.time.Clock() 
	screen = pygame.display.set_mode((windows_width, windows_height)) #
	screen.fill(white)


	pygame.display.set_caption(r"Python 贪吃蛇小游戏") 
	show_start_info(screen)              
	while True:
		pygame.mixer.music.load("1.mp3")
		pygame.mixer.music.play(-1)
		running_game(screen, snake_speed_clock)
		show_gameover_info(screen)


def running_game(screen,snake_speed_clock):
	startx = random.randint(3, map_width - 8) #开始位置
	starty = random.randint(3, map_height - 8)
	snake_coords = [{'x': startx, 'y': starty},  #初始贪吃蛇
                  {'x': startx - 1, 'y': starty},
                  {'x': startx - 2, 'y': starty}]

	direction = RIGHT       #  开始时向右移动

	food = []
	a=number
	while a>0:
		food.append(get_random_location())
		a=a-1
	Barrier = []
	Barrier.append({'x':8,'y':21})
	Barrier.append({'x': 12, 'y': 21})
	Barrier.append({'x': 16, 'y': 21})
	Barrier.append({'x': 20, 'y': 21})
	Barrier.append({'x': 24, 'y': 21})
	Barrier.append({'x': 28, 'y': 21})
	Barrier.append({'x': 32, 'y': 21})
	Barrier.append({'x': 8, 'y': 17})
	Barrier.append({'x': 8, 'y': 13})
	Barrier.append({'x': 8, 'y': 9})
	Barrier.append({'x': 32, 'y': 17})
	Barrier.append({'x': 32, 'y': 13})
	Barrier.append({'x': 32, 'y': 9})
	Barrier.append({'x': 12, 'y': 9})
	Barrier.append({'x': 16, 'y': 9})
	Barrier.append({'x': 20, 'y': 9})
	Barrier.append({'x': 24, 'y': 9})
	Barrier.append({'x': 28, 'y': 9})

#	print(Barrier)
#	Barrier.append({'x':Barrier[0][x]+1, 'y':Barrier[0][y]})
#	Barrier.append(Barrier[1] + 1)
#	Barrier.append(Barrier[2] + 1)
	

	while True:
		for event in pygame.event.get():
			if event.type == QUIT:
				terminate()
			elif event.type == KEYDOWN:
				if (event.key == K_LEFT or event.key == K_a) and direction != RIGHT:
					direction = LEFT
				elif (event.key == K_RIGHT or event.key == K_d) and direction != LEFT:
					direction = RIGHT
				elif (event.key == K_UP or event.key == K_w) and direction != DOWN:
					direction = UP
				elif (event.key == K_DOWN or event.key == K_s) and direction != UP:
					direction = DOWN
				elif event.key == K_ESCAPE:
					terminate()

		move_snake(direction, snake_coords) #移动蛇

		ret = snake_is_alive(snake_coords,Barrier)
		mx(int(ret), len(snake_coords) - 4)#这个是排行榜
		if not ret:
			break #蛇跪了. 游戏结束
	#	snake_is_eat_food(snake_coords, food1, food2) #判断蛇是否吃到食物
	#	snake_is_eat_food(snake_coords, food3, food4)

		screen.fill(BG_COLOR)
		draw_grid(screen)
		draw_snake(screen, snake_coords)
		for i in range(18):
			draw_barrier(screen, Barrier[i-1])
#		draw_food(screen, food1, food2)
#		draw_food(screen, food3, food4)
		b=number
		while b>0:
			draw_food(screen,food[b-1])
			b=b-1
		draw_score(screen, len(snake_coords) - 4)
		snake_is_eat_food(snake_coords, food, Barrier)
		pygame.display.update()
		snake_speed_clock.tick(snake_speed) #控制fps

def draw_barrier(screen , Barrier):
        x = Barrier['x'] * cell_size
        y = Barrier['y'] * cell_size
        BarrierRect = pygame.Rect(x, y, cell_size, cell_size)
        pygame.draw.rect(screen, black, BarrierRect)

def mx(x, s):#排行榜函数
    if x != 1:
        str1 = time.strftime('%Y.%m.%d %H:%M:%S', time.localtime(time.time()))
        file_handle = open('date.txt', mode='a+')
        if int(s) < 10:
            file_handle.write('得分:0%s    日期: %s\n' % (s, str1))
        else:
            file_handle.write('得分:%s    日期: %s\n' % (s, str1))
        file_handle.close()

def draw_food(screen, food):#把食物画出来,两个食物
    x = food['x'] * cell_size
    y = food['y'] * cell_size
    appleRect = pygame.Rect(x, y, cell_size, cell_size)
    pygame.draw.rect(screen, Red, appleRect)



#将贪吃蛇画出来
def draw_snake(screen, snake_coords):
	for coord in snake_coords:
		x = coord['x'] * cell_size
		y = coord['y'] * cell_size
		wormSegmentRect = pygame.Rect(x, y, cell_size, cell_size)
		pygame.draw.rect(screen, dark_blue, wormSegmentRect)
		wormInnerSegmentRect = pygame.Rect(                #蛇身子里面的第二层亮绿色
			x + 4, y + 4, cell_size - 8, cell_size - 8)
		pygame.draw.rect(screen, blue, wormInnerSegmentRect)
#画网格(可选)
def draw_grid(screen):
	for x in range(0, windows_width, cell_size):  # draw 水平 lines
		pygame.draw.line(screen, dark_gray, (x, 0), (x, windows_height))
	for y in range(0, windows_height, cell_size):  # draw 垂直 lines
		pygame.draw.line(screen, dark_gray, (0, y), (windows_width, y))
#移动贪吃蛇
def move_snake(direction, snake_coords):
    if direction == UP:
        newHead = {'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y'] - 1}
    elif direction == DOWN:
        newHead = {'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y'] + 1}
    elif direction == LEFT:
        newHead = {'x': snake_coords[HEAD]['x'] - 1, 'y': snake_coords[HEAD]['y']}
    elif direction == RIGHT:
        newHead = {'x': snake_coords[HEAD]['x'] + 1, 'y': snake_coords[HEAD]['y']}

    snake_coords.insert(0, newHead)
#判断蛇死了没
def snake_is_alive(snake_coords,Barrier):
	tag = True
	if snake_coords[HEAD]['x'] == -1 or snake_coords[HEAD]['x'] == map_width or snake_coords[HEAD]['y'] == -1 or \
			snake_coords[HEAD]['y'] == map_height:
		tag = False # 蛇碰壁啦
	if ({'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y']} in Barrier):
		tag = False
	for snake_body in snake_coords[1:]:
		if snake_body['x'] == snake_coords[HEAD]['x'] and snake_body['y'] == snake_coords[HEAD]['y']:
			tag = False # 蛇碰到自己身体啦
	return tag

def snake_is_eat_food(snake_coords, food, Barrier):  #如果是列表或字典,那么函数内修改参数内容,就会影响到函数体外的对象。
        if ({'x':snake_coords[HEAD]['x'], 'y':snake_coords[HEAD]['y']} in food):
                music.play()
                x = food.index({'x':snake_coords[HEAD]['x'], 'y':snake_coords[HEAD]['y']})
                food[x]['x'] = random.randint(0, map_width - 1)
                food[x]['y'] = random.randint(0, map_height - 1)
                while  ({'x':food[x]['x'],'y':food[x]['y']} in Barrier):
                        food[x]['x'] = random.randint(0, map_width -1)
                        food[x]['y'] = random.randint(0, map_height - 1)
        else:
                del snake_coords[-1]  # 如果没有吃到实物, 就向前移动, 那么尾部一格删掉




#食物随机生成
def get_random_location():
	return {'x': random.randint(0, map_width - 1), 'y': random.randint(0, map_height - 1)}
#开始信息显示
def show_start_info(screen):
        
	font = pygame.font.Font('myfont.ttf', 40)
	tip = font.render('按任意键开始游戏~~~', True, (65, 105, 225))
	x = random.randint(0,100)
	x = x % 3
	if x == 0:
                gamestart = pygame.image.load('gamestart1.png')
	elif x == 1 :
                gamestart = pygame.image.load('gamestart2.png')
	else :
                gamestart = pygame.image.load('gamestart3.png')
	screen.blit(gamestart, (140, 30))
	screen.blit(tip, (240, 550))
	pygame.display.update()

	while True:  #键盘监听事件
		for event in pygame.event.get():  # event handling loop
			if event.type == QUIT:
				terminate()     #终止程序
			elif event.type == KEYDOWN:
				if (event.key == K_ESCAPE):  #终止程序
					terminate() #终止程序
				else:
					return #结束此函数, 开始游戏
#游戏结束信息显示
def show_gameover_info(screen):
	pygame.mixer.music.load("3.mp3")
	pygame.mixer.music.play()
	font = pygame.font.Font('myfont.ttf', 40)
	tip = font.render('按Q或者ESC退出游戏, 按M键重新开始游戏~', True, (65, 105, 225))
	x = random.randint(0,100)
	x = x % 3
	if x == 0 :
		gamestart = pygame.image.load('gameover1.png')
	elif x == 1 :
		gamestart = pygame.image.load('gameover2.png')
	else :
		gamestart = pygame.image.load('gameover3.png')
	screen.blit(gamestart, (60, 0))
	screen.blit(tip, (80, 300))
	pygame.display.update()

	while True:  #键盘监听事件
		for event in pygame.event.get():  # event handling loop
			if event.type == QUIT:
				terminate()     #终止程序
			elif event.type == KEYDOWN:
				if event.key == K_ESCAPE or event.key == K_q:  #终止程序
					terminate() #终止程序
				if event.key == K_m:
					return #结束此函数, 重新开始游戏
#画成绩
def draw_score(screen,score):
	font = pygame.font.Font('myfont.ttf', 30)
	scoreSurf = font.render('得分: %s' % score, True, Green)
	scoreRect = scoreSurf.get_rect()
	scoreRect.topleft = (windows_width - 120, 10)
	screen.blit(scoreSurf, scoreRect)
#程序终止
def terminate():
	pygame.quit()
	sys.exit()


main()

3.AI版

#1.添加音乐、吃到食物音效
#2.添加多个食物(5个)
#**3.修改对抗规则:玩家控制蛇撞到电脑控制蛇会死亡
#4.修改电脑获取食物坐标机制,暂时定于计算机遍历每个坐标与食物坐标对比获得
#5.修改游戏规则,谁先到达一定长度谁赢
######################################################################
####################*************************#########################
######################################################################
import random
import pygame
import sys

from pygame.locals import *

snake_speed = 10 #贪吃蛇的速度
windows_width = 800
windows_height = 600 #游戏窗口的大小
cell_size = 20       #贪吃蛇身体方块大小,注意身体大小必须能被窗口长宽整除

assert windows_width % cell_size == 0
assert windows_height % cell_size == 0

''' #初始化区
由于我们的贪吃蛇是有大小尺寸的, 因此地图的实际尺寸是相对于贪吃蛇的大小尺寸而言的
'''
map_width = int(windows_width / cell_size)
map_height = int(windows_height / cell_size)

# 颜色定义
white = (255, 255, 255)
black = (0, 0, 0)
gray = (230, 230, 230)
dark_gray = (40, 40, 40)
DARKGreen = (0, 155, 0)
Green = (0, 255, 0)
Red = (255, 0, 0)
blue = (0, 0, 255)
dark_blue =(0,0, 139)


BG_COLOR = black #游戏背景颜色
pygame.mixer.init()
music = pygame.mixer.Sound("2.wav")

UP = 1
DOWN = 2
LEFT = 3
RIGHT = 4

HEAD = 0 

#主函数
def main():
    pygame.init() 
    snake_speed_clock = pygame.time.Clock() 
    screen = pygame.display.set_mode((windows_width, windows_height)) #
    screen.fill(white)

    pygame.display.set_caption("Python 贪吃蛇小游戏")
    show_start_info(screen)            
    while True:
        pygame.mixer.music.load("1.mp3")
        pygame.mixer.music.play(-1)
        running_game(screen, snake_speed_clock)
        #run_game_AI(screen, snake_speed_clock)
        

#上1下2左3右4
#游戏运行主体
def running_game(screen,snake_speed_clock):
    board = [0] * FIELD_SIZE
    startx = 3 
    starty = 5
    snake_coords1 = [{'x': startx, 'y': starty},
                  {'x': startx - 1, 'y': starty},
                  {'x': startx - 2, 'y': starty}]
    snake_coords = [{'x': startx, 'y': starty+10}, #人控制的
                  {'x': startx - 1, 'y': starty},
                  {'x': startx - 2, 'y': starty}]

    direction = RIGHT    
    direction1 = RIGHT    

    food = []
    a = 5
    shoot = False
    bongLocate = snake_coords1[HEAD]
    bongDirection = LEFT
    live = True
    while a>0:
        food.append(get_random_location())
        a=a-1
    while True:
        for event in pygame.event.get():
            if event.type == QUIT:
                terminate()
            elif event.type == KEYDOWN:
                if (event.key == K_LEFT or event.key == K_a) and direction1 != RIGHT:
                    direction1 = LEFT
                elif (event.key == K_RIGHT or event.key == K_d) and direction1 != LEFT:
                    direction1 = RIGHT
                elif (event.key == K_UP or event.key == K_w) and direction1 != DOWN:
                    direction1 = UP
                elif (event.key == K_DOWN or event.key == K_s) and direction1 != UP:
                    direction1 = DOWN
                elif event.key == K_ESCAPE:
                    terminate()
                elif event.key == K_SPACE:
                    if shoot == False and len(snake_coords1) > 3:
                        shoot = True
                        del snake_coords1[-1]
                        bongDirection = direction1
                        if bongDirection == 1 :
                            bongLocate['x'] = snake_coords1[HEAD]['x'] 
                            bongLocate['y'] = snake_coords1[HEAD]['y'] - 2
                        if bongDirection == 2 :
                            bongLocate['x'] = snake_coords1[HEAD]['x'] 
                            bongLocate['y'] = snake_coords1[HEAD]['y'] + 2
                        if bongDirection == 3 :
                            bongLocate['x'] = snake_coords1[HEAD]['x'] - 2
                            bongLocate['y'] = snake_coords1[HEAD]['y']
                        if bongDirection == 4 :
                            bongLocate['x'] = snake_coords1[HEAD]['x'] + 2
                            bongLocate['y'] = snake_coords1[HEAD]['y'] 
                        

                        

        food_location = find_food(food)
        #if len(snake_coords) > 9:
         #   live = False
        if not live and len(snake_coords) > 4:            
            #board[head_idx] = SNAKE_PLACE
            #board[end_idx] = FREE_PLACE
            del snake_coords[-1]
            del snake_coords[-1]
            del snake_coords[-1]
            del snake_coords[-1]
            #del snake_coords[-1]
            shoot = False
            live = True
#        print(food_location)


        reset_board = board_reset(snake_coords, board, food_location)
        board = reset_board
        result, refresh_board = board_refresh(snake_coords, food_location, board)
        board = refresh_board
        # 如果蛇可以吃到食物
        if result:
            best_move = find_safe_way(snake_coords, board, food_location)
        else:
            best_move = follow_tail(snake_coords, board, food_location)
        if best_move == ERR:
            best_move = any_possible_move(snake_coords, board, food_location)
        if best_move != ERR:
            newHead = find_snake_head(snake_coords, best_move)
            snake_coords.insert(0, newHead)
            head_idx = snake_coords[HEAD]['x'] + snake_coords[HEAD]['y']*map_width
            end_idx = snake_coords[-1]['x'] + snake_coords[-1]['y']*map_width
            if ({'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y']} in food):
                board[head_idx] = SNAKE_PLACE
                if len(snake_coords) < FIELD_SIZE:
                    xx = food.index({'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y']})
                    food[xx]['x'] = random.randint(0, map_width - 1)
                    food[xx]['y'] = random.randint(0, map_height - 1)
            else:
                board[head_idx] = SNAKE_PLACE
                board[end_idx] = FREE_PLACE
                del snake_coords[-1]

        else:
            return

        move_snake(direction1, snake_coords1) #移动蛇 
#        print(snake_speed)
#        print(food_location)
#        print(m)


        snake_is_eat_food(snake_coords1, food) #判断蛇是否吃到食物
        screen.fill(BG_COLOR)
        #print(bongDirection)
        if shoot:
            #print(bongLocate)
            draw_bong(screen, bongLocate)
            if bongDirection == 1 :
                bongLocate['y'] = bongLocate['y'] - 1
            elif bongDirection == 2 :
                bongLocate['y'] = bongLocate['y'] + 1
            elif bongDirection == 3:
                bongLocate['x'] = bongLocate['x'] - 1
            elif bongDirection == 4 :
                bongLocate['x'] = bongLocate['x'] + 1
            live = AIanake_is_alive(snake_coords,bongLocate)#判断AI贪吃蛇死了没
            if bongLocate['x'] <= -1 or bongLocate['x'] >= map_width or bongLocate['y'] <= -1 or bongLocate['y'] >= map_height :
                shoot = False
         #   del snake_coords[-5]
            #gameover(screen)
            #break
        draw_score(screen, len(snake_coords) - 3, len(snake_coords1)-3)
        #print(len(snake_coords))
        ret = snake_is_alive(snake_coords1, snake_coords)
        #ret = True
        if not ret or len(snake_coords)-3 == 30 or len(snake_coords1)-3 == 30:
            show_gameover_info(screen, len(snake_coords) -3, len(snake_coords1)-3,ret)
            break  # 蛇跪了. 游戏结束
        draw_snake(screen, snake_coords)
        draw_snake1(screen, snake_coords1)
        a=5
        while a>0:
            draw_food(screen, food[a-1])
            a=a-1
        pygame.display.update()
        snake_speed_clock.tick(10)

def draw_bong(screen, bong):
    x = bong['x'] * cell_size
    y = bong['y'] * cell_size
    bongRect = pygame.Rect(x, y, cell_size, cell_size)
    pygame.draw.rect(screen, Green, bongRect)
    

def find_food(food):
    for x in range(windows_height):
            for y in range(windows_width):
                if ({'x':x, 'y':y} in food):
                    m = food.index({'x': x, 'y': y})
                    return food[m]

def draw_food(screen, food):
	x = food['x'] * cell_size
	y = food['y'] * cell_size
	appleRect = pygame.Rect(x, y, cell_size, cell_size)
	pygame.draw.rect(screen, Red, appleRect)
#将贪吃蛇画出来
def draw_snake(screen, snake_coords):
    for coord in snake_coords:
        x = coord['x'] * cell_size
        y = coord['y'] * cell_size
        wormSegmentRect = pygame.Rect(x, y, cell_size, cell_size)
        pygame.draw.rect(screen, dark_blue, wormSegmentRect)
        wormInnerSegmentRect = pygame.Rect(               
            x + 4, y + 4, cell_size - 8, cell_size - 8)
        pygame.draw.rect(screen, blue, wormInnerSegmentRect)
def draw_snake1(screen, snake_coords):
    for coord in snake_coords:
        x = coord['x'] * cell_size
        y = coord['y'] * cell_size
        wormSegmentRect = pygame.Rect(x, y, cell_size, cell_size)
        pygame.draw.rect(screen, dark_blue, wormSegmentRect)
        wormInnerSegmentRect = pygame.Rect( 
            x + 4, y + 4, cell_size - 8, cell_size - 8)
        pygame.draw.rect(screen, Red, wormInnerSegmentRect)

#移动贪吃蛇
def move_snake(direction, snake_coords):
    if direction == UP:
        newHead = {'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y'] - 1}
    elif direction == DOWN:
        newHead = {'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y'] + 1}
    elif direction == LEFT:
        newHead = {'x': snake_coords[HEAD]['x'] - 1, 'y': snake_coords[HEAD]['y']}
    elif direction == RIGHT:
        newHead = {'x': snake_coords[HEAD]['x'] + 1, 'y': snake_coords[HEAD]['y']}

    snake_coords.insert(0, newHead)
    
def AIanake_is_alive(snake,bong):
    tag = True
    for snake_body in snake[1:]:
        if snake_body['x'] == bong['x'] and snake_body['y'] == bong['y']:
            #print('被打到了')
            #print(len(snake))
            #del snake[-5]
            tag = False
    return tag

#判断蛇死了没
def snake_is_alive(snake_coords1,snake_coords):
    tag = True
    if snake_coords1[HEAD]['x'] == -1 or snake_coords1[HEAD]['x'] == map_width or snake_coords1[HEAD]['y'] == -1 or \
            snake_coords1[HEAD]['y'] == map_height:
        tag = False # 蛇碰壁啦
    for snake_body in snake_coords1[1:]:
        if snake_body['x'] == snake_coords1[HEAD]['x'] and snake_body['y'] == snake_coords1[HEAD]['y']:
            tag = False # 蛇碰到自己身体啦
    for snake_body in snake_coords[1:]:
        if snake_body['x'] == snake_coords1[HEAD]['x'] and snake_body['y'] == snake_coords1[HEAD]['y']:
            tag = False
    return tag
#判断贪吃蛇是否吃到食物
def snake_is_eat_food(snake_coords, food): 
        if ({'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y']} in food):
            music.play()
            x = food.index({'x': snake_coords[HEAD]['x'], 'y': snake_coords[HEAD]['y']})
            food[x]['x'] = random.randint(0, map_width - 1)
            food[x]['y'] = random.randint(0, map_height - 1)
        else:
            del snake_coords[-1]  # 如果没有吃到实物, 就向前移动, 那么尾部一格删掉
#食物随机生成
def get_random_location():
    return {'x': random.randint(0, map_width -1), 'y': random.randint(0, map_height -1)}



def show_start_info(screen):
    font = pygame.font.Font('myfont.ttf', 40)
    tip = font.render('按任意键开始游戏~~~', True, (65, 105, 225))
    x = random.randint(0,100)
    x = x % 3
    if x == 0:
        gamestart = pygame.image.load('gamestart1.png')
    elif x == 1:
        gamestart = pygame.image.load('gamestart2.png')
    else :
        gamestart = pygame.image.load('gamestart3.png')
    #print(x%3)
    screen.blit(gamestart, (140, 30))
    screen.blit(tip, (240, 550))
    pygame.display.update()

    while True:  #键盘监听事件
        for event in pygame.event.get(): 
            if event.type == QUIT:
                terminate()     #终止程序
            elif event.type == KEYDOWN:
                if (event.key == K_ESCAPE):  #终止程序
                    terminate() #终止程序
                else:
                    return #结束此函数, 开始游戏

#游戏结束信息显示
def show_gameover_info(screen,s1,s2,ret):
    font = pygame.font.Font('myfont.ttf', 40)
    font_x=pygame.font.Font('myfont.ttf',80)
    if s1<s2 and ret:
        tips = font_x.render('玩家胜利',True,Red)
        pygame.mixer.music.load("4.mp3")
        pygame.mixer.music.play()        
    elif s1==s2 and ret:
        tips = font_x.render('平局',True,Red)
        pygame.mixer.music.load("4.mp3")
        pygame.mixer.music.play()
    else:
        tips = font_x.render('计算机胜利',True,Red)
        pygame.mixer.music.load("3.mp3")
        pygame.mixer.music.play()
    tip = font.render('按Q或者ESC退出游戏, 按任意键重新开始游戏~', True, (65, 105, 225))
    x = random.randint(0,100)
    x = x % 3
    if x == 0:
        gamestart = pygame.image.load('gameover1.png')
    elif x == 1:
        gamestart = pygame.image.load('gameover2.png')
    else  :
        gamestart = pygame.image.load('gameover3.png')
    screen.blit(gamestart, (60, 0))
    screen.blit(tip, (80, 300))
    screen.blit(tips, (300, 200))
    pygame.display.update()

    while True:  #键盘监听事件
        for event in pygame.event.get():  # event handling loop
            if event.type == QUIT:
                terminate()     #终止程序
            elif event.type == KEYDOWN:
                if event.key == K_ESCAPE or event.key == K_q:  #终止程序
                    terminate() #终止程序
                else:
                    return #结束此函数, 重新开始游戏
#画成绩
def draw_score(screen,score1,score2):
    font = pygame.font.Font('myfont.ttf', 30)
    scoreSurf1 = font.render('计算机得分: %s' % score1, True, Green)
    scoreSurf2 = font.render("玩家得分:%s" % score2, True , Green)
    scoreRect1 = scoreSurf1.get_rect()
    scoreRect2 = scoreSurf2.get_rect()
    scoreRect1.topright = (windows_width - 600, 10)
    scoreRect2.topleft = (windows_width -180,10)
 #   scoreRect.topleft 
    screen.blit(scoreSurf1, scoreRect1)
    screen.blit(scoreSurf2,scoreRect2)
#程序终止
def terminate():
    pygame.quit()
    sys.exit()



    
# 运动方向字典
move_directions = {
					'left': -1,
					'right': 1,
					'up': -map_width,
					'down': map_width
					}



def Is_Cell_Free(idx, psnake):
    location_x = idx % map_width
    location_y = idx // map_width
    idx = {'x': location_x, 'y': location_y}
    return (idx not in psnake)

# 检查位置idx是否可以向当前move方向运动
def is_move_possible(idx, move_direction):
    flag = False
    if move_direction == 'left':
        if idx % map_width > 0:
            flag = True
        else:
            flag = False
    elif move_direction == 'right':
        if idx % map_width < map_width-1:
            flag = True
        else:
            flag = False
    elif move_direction == 'up':
        if idx > map_width-1:
            flag = True
        else:
            flag = False
    elif move_direction == 'down':
        if idx < FIELD_SIZE - map_width:
            flag = True
        else:
            flag = False
    return flag

# 广度优先搜索遍历整个board
# 计算出board中每个非SNAKE_PLACE元素到达食物的路径长度
def board_refresh(psnake, pfood, pboard):
    temp_board = pboard[:]
    pfood_idx = pfood['x'] + pfood['y'] * map_width
    queue = []
    queue.append(pfood_idx)
    inqueue = [0] * FIELD_SIZE
    found = False
    while len(queue) != 0:
        idx = queue.pop(0)
        if inqueue[idx] == 1:
            continue
        inqueue[idx] = 1
        for move_direction in ['left', 'right', 'up', 'down']:
            if is_move_possible(idx, move_direction):
                if (idx+move_directions[move_direction]) == (psnake[HEAD]['x'] + psnake[HEAD]['y']*map_width):
                    found = True
                # 该点不是蛇身(食物是0才可以这样子写)
                if temp_board[idx+move_directions[move_direction]] < SNAKE_PLACE:
                    if temp_board[idx+move_directions[move_direction]] > temp_board[idx]+1:
                        temp_board[idx+move_directions[move_direction]] = temp_board[idx] + 1
                    if inqueue[idx+move_directions[move_direction]] == 0:
                        queue.append(idx+move_directions[move_direction])
    return (found, temp_board)


# 根据board中元素值
# 从蛇头周围4个领域点中选择最短路径
def choose_shortest_safe_move(psnake, pboard):
    best_move = ERR
    min_distance = SNAKE_PLACE
    for move_direction in ['left', 'right', 'up', 'down']:
        idx = psnake[HEAD]['x'] + psnake[HEAD]['y']*map_width
        if is_move_possible(idx, move_direction) and (pboard[idx+move_directions[move_direction]]<min_distance):
            min_distance = pboard[idx+move_directions[move_direction]]
            best_move = move_direction
    return best_move


# 找到移动后蛇头的位置
def find_snake_head(snake_Coords, direction):
    if direction == 'up':
        newHead = {'x': snake_Coords[HEAD]['x'],
                   'y': snake_Coords[HEAD]['y']-1}
    elif direction == 'down':
        newHead = {'x': snake_Coords[HEAD]['x'],
                   'y': snake_Coords[HEAD]['y']+1}
    elif direction == 'left':
        newHead = {'x': snake_Coords[HEAD]['x']-1,
                   'y': snake_Coords[HEAD]['y']}
    elif direction == 'right':
        newHead = {'x': snake_Coords[HEAD]['x']+1,
                   'y': snake_Coords[HEAD]['y']}
    return newHead


# 虚拟地运行一次
def virtual_move(psnake, pboard, pfood):
    temp_snake = psnake[:]
    temp_board = pboard[:]
    reset_tboard = board_reset(temp_snake, temp_board, pfood)
    temp_board = reset_tboard
    food_eated = False
    while not food_eated:
        refresh_tboard = board_refresh(temp_snake, pfood, temp_board)[1]
        temp_board = refresh_tboard
        move_direction = choose_shortest_safe_move(temp_snake, temp_board)
        snake_Coords = temp_snake[:]
        temp_snake.insert(0, find_snake_head(snake_Coords, move_direction))
        # 如果新的蛇头正好是食物的位置
        if temp_snake[HEAD] == pfood:
            reset_tboard = board_reset(temp_snake, temp_board, pfood)
            temp_board = reset_tboard
            pfood_idx = pfood['x'] + pfood['y'] * map_width
            temp_board[pfood_idx] = SNAKE_PLACE
            food_eated = True
        else:
            newHead_idx = temp_snake[0]['x'] + temp_snake[0]['y'] * map_width
            temp_board[newHead_idx] = SNAKE_PLACE
            end_idx = temp_snake[-1]['x'] + temp_snake[-1]['y'] * map_width
            temp_board[end_idx] = FREE_PLACE
            del temp_snake[-1]
    return temp_snake, temp_board


# 检查蛇头和蛇尾间是有路径的
# 避免蛇陷入死路
def is_tail_inside(psnake, pboard, pfood):
    temp_board = pboard[:]
    temp_snake = psnake[:]
    # 将蛇尾看作食物
    end_idx = temp_snake[-1]['x'] + temp_snake[-1]['y'] * map_width
    temp_board[end_idx] = FOOD
    v_food = temp_snake[-1]
    # 食物看作蛇身(重复赋值了)
    pfood_idx = pfood['x'] + pfood['y'] * map_width
    temp_board[pfood_idx] = SNAKE_PLACE
    # 求得每个位置到蛇尾的路径长度
    result, refresh_tboard = board_refresh(temp_snake, v_food, temp_board)
    temp_board = refresh_tboard
    for move_direction in ['left', 'right', 'up', 'down']:
        idx = temp_snake[HEAD]['x'] + temp_snake[HEAD]['y']*map_width
        end_idx = temp_snake[-1]['x'] + temp_snake[-1]['y']*map_width
        if is_move_possible(idx, move_direction) and (idx+move_directions[move_direction] == end_idx) and (len(temp_snake)>3):
            result = False
    return result


# 根据board中元素值
# 从蛇头周围4个领域点中选择最远路径
def choose_longest_safe_move(psnake, pboard):
    best_move = ERR
    max_distance = -1
    for move_direction in ['left', 'right', 'up', 'down']:
        idx = psnake[HEAD]['x'] + psnake[HEAD]['y']*map_width
        if is_move_possible(idx, move_direction) and (pboard[idx+move_directions[move_direction]]>max_distance) and (pboard[idx+move_directions[move_direction]]<FREE_PLACE):
            max_distance = pboard[idx+move_directions[move_direction]]
            best_move = move_direction
    return best_move 


# 让蛇头朝着蛇尾运行一步
def follow_tail(psnake, pboard, pfood):
    temp_snake = psnake[:]
    temp_board = board_reset(temp_snake, pboard, pfood)
    # 将蛇尾看作食物
    end_idx = temp_snake[-1]['x'] + temp_snake[-1]['y'] * map_width
    temp_board[end_idx] = FOOD
    v_food = temp_snake[-1]
    # 食物看作蛇身
    pfood_idx = pfood['x'] + pfood['y'] * map_width
    temp_board[pfood_idx] = SNAKE_PLACE
    # 求得每个位置到蛇尾的路径长度
    result, refresh_tboard = board_refresh(temp_snake, v_food, temp_board)
    temp_board = refresh_tboard
    # 还原
    temp_board[end_idx] = SNAKE_PLACE
    # temp_board[pfood_idx] = FOOD
    return choose_longest_safe_move(temp_snake, temp_board)


# 如果蛇和食物间有路径
# 则需要找一条安全的路径
def find_safe_way(psnake, pboard, pfood):
    safe_move = ERR
    real_snake = psnake[:]
    real_board = pboard[:]
    v_psnake, v_pboard = virtual_move(psnake, pboard, pfood)
    # 如果虚拟运行后,蛇头蛇尾间有通路,则选最短路运行
    if is_tail_inside(v_psnake, v_pboard, pfood):
        safe_move = choose_shortest_safe_move(real_snake, real_board)
    else:
        safe_move = follow_tail(real_snake, real_board, pfood)
    return safe_move


# 各种方案均无效时,随便走一步
def any_possible_move(psnake, pboard, pfood):
    best_move = ERR
    reset_board = board_reset(psnake, pboard, pfood)
    pboard = reset_board
    result, refresh_board = board_refresh(psnake, pfood, pboard)
    pboard = refresh_board
    min_distance = SNAKE_PLACE
    for move_direction in ['left', 'right', 'up', 'down']:
        idx = psnake[HEAD]['x'] + psnake[HEAD]['y']*map_width
        if is_move_possible(idx, move_direction) and (pboard[idx+move_directions[move_direction]]<min_distance):
            min_distance = pboard[idx+move_directions[move_direction]]
            best_move = move_direction
    return best_move


# 重置board
def board_reset(psnake, pboard, pfood):
    temp_board = pboard[:]
    pfood_idx = pfood['x'] + pfood['y'] * map_width
    for i in range(FIELD_SIZE):
        if i == pfood_idx:
            temp_board[i] = FOOD
        elif Is_Cell_Free(i, psnake):
            temp_board[i] = FREE_PLACE
        else:
            temp_board[i] = SNAKE_PLACE
    return temp_board

# 错误码
ERR = -404

FIELD_SIZE = map_width * map_height
# 运动方向
best_move = ERR
# 不同东西在矩阵里用不同的数字表示
FOOD = 0
FREE_PLACE = (map_width+1) * (map_height+1)
SNAKE_PLACE = 2 * FREE_PLACE
    

if __name__ == '__main__':
    main()