上传文件至 /
搓了一个充满bug的算法框架
This commit is contained in:
parent
9a01b8eb29
commit
4738b5c4ff
4
.gitignore
vendored
4
.gitignore
vendored
@ -1,3 +1,3 @@
|
||||
__pycache__/
|
||||
idea.km
|
||||
__pycache__/
|
||||
idea.km
|
||||
idea.png
|
84
ai.py
Normal file
84
ai.py
Normal file
@ -0,0 +1,84 @@
|
||||
from data_structure import Tree
|
||||
|
||||
class Ai:
|
||||
def __init__(self):
|
||||
self.path = []
|
||||
|
||||
def start(self,snake,apple,settings):
|
||||
openlist = []
|
||||
closelist = []
|
||||
starting_point = snake.coords[0]
|
||||
ending_point = apple.coords
|
||||
|
||||
|
||||
def calculate_f():
|
||||
"""计算openlist各格子的f值"""
|
||||
for cell in openlist:
|
||||
g = abs(cell['x'] - starting_point['x']) + abs(cell['y'] - starting_point['y'])
|
||||
h = abs(cell['x'] - ending_point['x']) + abs(cell['y'] - ending_point['y'])
|
||||
f = g + h
|
||||
cell['f'] = f
|
||||
|
||||
|
||||
def is_wall():
|
||||
# 碰到左右墙壁
|
||||
if (cell['x'] == -1 or cell['x'] == settings.cell_w):
|
||||
return True
|
||||
# 碰到上下墙壁
|
||||
if (cell['y'] == -1 or cell['y'] == settings.cell_h):
|
||||
return True
|
||||
# 碰到自己
|
||||
if (cell in snake.coords[1:]):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
#记得做openlist用尽、苹果在蛇里面的解决办法
|
||||
while ending_point not in openlist:
|
||||
if not openlist:
|
||||
openlist.append(starting_point)
|
||||
path_tree = Tree(starting_point)
|
||||
#查找Openlist中F最小的格子并弹入Closelist
|
||||
#《这里也有问题 假设下面出现的列表同步更改的错误解决了》
|
||||
#《那么本来就被计算过的格子不需要再次计算 但这里依然算了》
|
||||
calculate_f()
|
||||
min_f = min(f['f'] for f in openlist)
|
||||
for cell in openlist:
|
||||
if cell['f'] == min_f:
|
||||
closelist.append(cell)
|
||||
openlist.remove(cell)
|
||||
break
|
||||
#《这里有问题 不应该for 应该只检查刚丢进closelist的那一个》
|
||||
#《检查过的格子又检查一遍 也是openlist有重复格子的根本原因》
|
||||
for close_cell in closelist:
|
||||
near_cells = [{'x': close_cell['x'], 'y': close_cell['y'] + 1}, #获取旁边的格子上右下左
|
||||
{'x': close_cell['x'] + 1, 'y': close_cell['y']},
|
||||
{'x': close_cell['x'], 'y': close_cell['y'] - 1},
|
||||
{'x': close_cell['x'] - 1, 'y': close_cell['y']}]
|
||||
#不考虑蛇的身体或墙壁
|
||||
for cell in near_cells:
|
||||
if is_wall():
|
||||
near_cells.remove(cell)
|
||||
#排除F键值对的影响
|
||||
#《?为什么使用切片后copy的更改还是能影响到原openlist?》
|
||||
#《搞得我openlist的f值全弹出了》
|
||||
openlist_copy = openlist[:]
|
||||
for cell_copy in openlist_copy:
|
||||
cell_copy.pop('f',None)
|
||||
#找出不在openlist的格子并加进openlist
|
||||
#《filter疑似用错 没有筛选功能 openlist依然有重复格子》
|
||||
not_in_list = filter(lambda x: x != (cell_copy for cell_copy in openlist_copy), near_cells)
|
||||
openlist.extend(not_in_list)
|
||||
#《这里再用一次filter查教程后是因为filter只能迭代一次》
|
||||
#《filter好jb难用 我是因为看它性能消耗少才用的QAQ 换一个吧》
|
||||
not_in_list = filter(lambda x: x != (cell_copy for cell_copy in openlist_copy), near_cells)
|
||||
|
||||
#《这里的添加节点能运行但是加不进去 只有一开始的父节点加得进去》
|
||||
for not_in_cell in not_in_list:
|
||||
path_tree.add_child(path_tree.find(close_cell),not_in_cell)
|
||||
|
||||
|
||||
ending_nodes = path_tree.find(ending_point)
|
||||
for node in ending_nodes.get_ancestors()[::-1]:
|
||||
self.path.append(node)
|
||||
self.iterator = snake.create_iterator(self.path)
|
20
apple.py
20
apple.py
@ -1,11 +1,11 @@
|
||||
import random
|
||||
|
||||
|
||||
class Apple():
|
||||
def __init__(self,settings):
|
||||
self.x = random.randint(1, settings.cell_w - 1)
|
||||
self.y = random.randint(1, settings.cell_h - 1)
|
||||
|
||||
def spawn(self,settings):
|
||||
self.x = random.randint(1, settings.cell_w - 1)
|
||||
import random
|
||||
|
||||
|
||||
class Apple():
|
||||
def __init__(self,settings):
|
||||
self.x = 7#random.randint(1, settings.cell_w - 1)
|
||||
self.y = 5#random.randint(1, settings.cell_h - 1)
|
||||
self.coords = {'x':self.x,'y':self.y}
|
||||
def spawn(self,settings):
|
||||
self.x = random.randint(1, settings.cell_w - 1)
|
||||
self.y = random.randint(1, settings.cell_h - 1)
|
53
data_structure.py
Normal file
53
data_structure.py
Normal file
@ -0,0 +1,53 @@
|
||||
class TreeNode:
|
||||
def __init__(self, value, parent=None):
|
||||
self.value = value
|
||||
self.parent = parent
|
||||
self.children = []
|
||||
|
||||
def add_child(self, child_node):
|
||||
child_node.parent = self
|
||||
self.children.append(child_node)
|
||||
|
||||
def remove_child(self, child_node):
|
||||
self.children = [child for child in self.children if child is not child_node]
|
||||
child_node.parent = None
|
||||
|
||||
def __repr__(self, level=0):
|
||||
ret = "\t" * level + repr(self.value) + "\n"
|
||||
for child in self.children:
|
||||
ret += child.__repr__(level + 1)
|
||||
return ret
|
||||
|
||||
def get_ancestors(self):
|
||||
"""返回当前节点及其所有祖先节点"""
|
||||
ancestors = []
|
||||
node = self
|
||||
ancestors.append(node)
|
||||
while node.parent:
|
||||
ancestors.append(node.parent)
|
||||
node = node.parent
|
||||
return ancestors
|
||||
|
||||
class Tree:
|
||||
def __init__(self, root_value):
|
||||
self.root = TreeNode(root_value)
|
||||
|
||||
def add_child(self, parent_node, child_value):
|
||||
if not parent_node:
|
||||
parent_node = self.root
|
||||
parent_node.add_child(TreeNode(child_value))
|
||||
|
||||
def find(self, value):
|
||||
return self._find_in_node(self.root, value)
|
||||
|
||||
def _find_in_node(self, node, value):
|
||||
if node.value == value:
|
||||
return node
|
||||
for child in node.children:
|
||||
found_node = self._find_in_node(child, value)
|
||||
if found_node:
|
||||
return found_node
|
||||
return None
|
||||
|
||||
def __repr__(self):
|
||||
return repr(self.root)
|
@ -1,168 +1,199 @@
|
||||
import pygame
|
||||
import sys
|
||||
|
||||
|
||||
def check_events(settings):
|
||||
for event in pygame.event.get():
|
||||
# 当按关闭或者按ESC键退出游戏
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_ESCAPE:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
# 按1键选择手动模式
|
||||
elif event.key == pygame.K_1:
|
||||
settings.game_mode = 1
|
||||
# 按2键选择自动模式
|
||||
elif event.key == pygame.K_2:
|
||||
settings.game_mode = 2
|
||||
|
||||
|
||||
def check_play_events(snake):
|
||||
"""检测游戏过程中的按键"""
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_ESCAPE:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
elif event.key == pygame.K_LEFT and not snake.direction == 'right': #防止反向移动
|
||||
snake.direction = 'left'
|
||||
break
|
||||
elif event.key == pygame.K_RIGHT and not snake.direction == 'left':
|
||||
snake.direction = 'right'
|
||||
break
|
||||
elif event.key == pygame.K_UP and not snake.direction == 'down':
|
||||
snake.direction = 'up'
|
||||
break
|
||||
elif event.key == pygame.K_DOWN and not snake.direction == 'up':
|
||||
snake.direction = 'down'
|
||||
break
|
||||
|
||||
|
||||
def show_start(settings, screen):
|
||||
"""模式选择界面"""
|
||||
title_Font = pygame.font.Font(settings.font_name, 80) # 设置标题字体
|
||||
title_image = title_Font.render("贪吃蛇", True, (255, 255, 255), (0, 0, 0))
|
||||
title_rect = title_image.get_rect()
|
||||
title_rect.center = screen.get_rect().center
|
||||
|
||||
presskey_font = pygame.font.Font(settings.font_name, 15) # 设置说明文字的字体
|
||||
presskey_image = presskey_font.render(
|
||||
'按1为手动模式,按2为自动模式,按ESC可退出游戏', True, (255, 255, 255), (0, 0, 0))
|
||||
presskey_rect = presskey_image.get_rect()
|
||||
presskey_rect.centerx = title_rect.centerx
|
||||
presskey_rect.top = title_rect.bottom
|
||||
|
||||
screen.fill(settings.bg_color) # 绘制屏幕
|
||||
screen.blit(title_image, title_rect) # 绘制标题
|
||||
screen.blit(presskey_image, presskey_rect) # 绘制说明文字
|
||||
while True:
|
||||
check_events(settings) # 检测键盘
|
||||
if settings.game_mode != 0: # 说明按了1或2,退出循环
|
||||
break
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
def show_end(settings, screen):
|
||||
"""失败结算界面"""
|
||||
title_font = pygame.font.Font(settings.font_name, 80)
|
||||
game_image = title_font.render('Game', True, (233, 150, 122))
|
||||
over_image = title_font.render('Over', True, (233, 150, 122))
|
||||
game_rect = game_image.get_rect()
|
||||
over_rect = over_image.get_rect()
|
||||
screen_rect = screen.get_rect()
|
||||
game_rect.midtop = (settings.width / 2, screen_rect.top + 70)
|
||||
over_rect.midtop = (settings.width / 2, game_rect.bottom + 50)
|
||||
screen.blit(game_image, game_rect)
|
||||
screen.blit(over_image, over_rect)
|
||||
pygame.display.flip()
|
||||
pygame.time.wait(1500)
|
||||
settings.game_mode = 0
|
||||
|
||||
|
||||
def draw_grid(settings, screen):
|
||||
# 绘制横向线
|
||||
for x in range(0, settings.width, settings.cell_size):
|
||||
pygame.draw.line(screen, (40, 40, 40), (x, 0), (x, settings.height))
|
||||
# 绘制竖向线
|
||||
for y in range(0, settings.height, settings.cell_size):
|
||||
pygame.draw.line(screen, (40, 40, 40), (0, y), (settings.width, y))
|
||||
|
||||
|
||||
def draw_snake(settings, screen, snake):
|
||||
# 头部用白色
|
||||
head_index = snake.coords[0]
|
||||
x = head_index['x'] * settings.cell_size
|
||||
y = head_index['y'] * settings.cell_size
|
||||
snake_head_rect = pygame.Rect(
|
||||
x, y, settings.cell_size, settings.cell_size)
|
||||
pygame.draw.rect(screen, (255, 255, 255), snake_head_rect)
|
||||
# 蛇身内部用浅绿,外框用深绿
|
||||
for bodies_index in snake.coords[1: -1]:
|
||||
x = bodies_index['x'] * settings.cell_size
|
||||
y = bodies_index['y'] * settings.cell_size
|
||||
snake_part_rect = pygame.Rect(
|
||||
x, y, settings.cell_size, settings.cell_size)
|
||||
pygame.draw.rect(screen, (0, 155, 0), snake_part_rect)
|
||||
snake_part_inner_rect = pygame.Rect(
|
||||
x + 4, y + 4, settings.cell_size - 8, settings.cell_size - 8)
|
||||
pygame.draw.rect(screen, (0, 255, 0), snake_part_inner_rect)
|
||||
# 蛇尾用浅绿
|
||||
tail_index = snake.coords[-1]
|
||||
x = tail_index['x'] * settings.cell_size
|
||||
y = tail_index['y'] * settings.cell_size
|
||||
snake_tail_rect = pygame.Rect(
|
||||
x, y, settings.cell_size, settings.cell_size)
|
||||
pygame.draw.rect(screen, (0, 255, 0), snake_tail_rect)
|
||||
|
||||
|
||||
def draw_apple(apple,settings,screen):
|
||||
x = apple.x * settings.cell_size
|
||||
y = apple.y * settings.cell_size
|
||||
apple_rect = pygame.Rect(
|
||||
x, y, settings.cell_size, settings.cell_size)
|
||||
pygame.draw.rect(screen, (255, 0, 0), apple_rect)
|
||||
|
||||
|
||||
# 绘制游戏界面
|
||||
def update_screen(settings, screen, snake,apple):
|
||||
screen.fill(settings.bg_color)
|
||||
draw_grid(settings, screen)
|
||||
draw_apple(apple,settings,screen)
|
||||
# 移动蛇
|
||||
snake.move_head() # 加蛇头
|
||||
if game_over(snake,settings):
|
||||
settings.game_mode = -1
|
||||
elif eat_apple(snake,apple):
|
||||
apple.spawn(settings)
|
||||
draw_apple(apple,settings,screen)
|
||||
else:
|
||||
del snake.coords[-1] # 去蛇尾
|
||||
draw_snake(settings, screen, snake)
|
||||
pygame.display.flip()
|
||||
# 暂停一下
|
||||
settings.my_clock.tick(settings.clock_frq)
|
||||
|
||||
|
||||
def game_over(snake,settings):
|
||||
# 碰到左右墙壁
|
||||
if (snake.coords[snake.head_index]['x'] == -1 or snake.coords[snake.head_index]['x'] == settings.cell_w):
|
||||
return True
|
||||
# 碰到上下墙壁
|
||||
if (snake.coords[snake.head_index]['y'] == -1 or snake.coords[snake.head_index]['y'] == settings.cell_h):
|
||||
return True
|
||||
# 碰到自己
|
||||
if (snake.coords[snake.head_index] in snake.coords[1:]):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def eat_apple(snake,apple):
|
||||
if (snake.coords[snake.head_index]['x'] == apple.x and snake.coords[snake.head_index]['y'] == apple.y):
|
||||
return True
|
||||
import pygame
|
||||
import sys
|
||||
|
||||
#函数名含义:check events for mode (selecting),下同
|
||||
def check_mode_events(settings):
|
||||
for event in pygame.event.get():
|
||||
# 当按关闭或者按ESC键退出游戏
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_ESCAPE:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
# 按1键选择手动模式
|
||||
elif event.key == pygame.K_1:
|
||||
settings.game_mode = 1
|
||||
# 按2键选择自动模式
|
||||
elif event.key == pygame.K_2:
|
||||
settings.game_mode = 2
|
||||
|
||||
|
||||
def check_play_events(snake):
|
||||
"""检测游戏过程中的按键"""
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_ESCAPE:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
elif event.key == pygame.K_LEFT and not snake.direction == 'right': #防止反向移动
|
||||
snake.direction = 'left'
|
||||
break
|
||||
elif event.key == pygame.K_RIGHT and not snake.direction == 'left':
|
||||
snake.direction = 'right'
|
||||
break
|
||||
elif event.key == pygame.K_UP and not snake.direction == 'down':
|
||||
snake.direction = 'up'
|
||||
break
|
||||
elif event.key == pygame.K_DOWN and not snake.direction == 'up':
|
||||
snake.direction = 'down'
|
||||
break
|
||||
|
||||
|
||||
def autocheck_events(ai,snake,apple,settings):
|
||||
for event in pygame.event.get():
|
||||
if event.type == pygame.QUIT:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
elif event.type == pygame.KEYDOWN:
|
||||
if event.key == pygame.K_ESCAPE:
|
||||
pygame.quit()
|
||||
sys.exit()
|
||||
if eat_apple(snake,apple):
|
||||
ai.start(snake,apple,settings)
|
||||
|
||||
def show_start(settings, screen):
|
||||
"""模式选择界面"""
|
||||
title_Font = pygame.font.Font(settings.font_name, 80) # 设置标题字体
|
||||
title_image = title_Font.render("贪吃蛇", True, (255, 255, 255), (0, 0, 0))
|
||||
title_rect = title_image.get_rect()
|
||||
title_rect.center = screen.get_rect().center
|
||||
|
||||
presskey_font = pygame.font.Font(settings.font_name, 15) # 设置说明文字的字体
|
||||
presskey_image = presskey_font.render(
|
||||
'按1为手动模式,按2为自动模式,按ESC可退出游戏', True, (255, 255, 255), (0, 0, 0))
|
||||
presskey_rect = presskey_image.get_rect()
|
||||
presskey_rect.centerx = title_rect.centerx
|
||||
presskey_rect.top = title_rect.bottom
|
||||
|
||||
screen.fill(settings.bg_color) # 绘制屏幕
|
||||
screen.blit(title_image, title_rect) # 绘制标题
|
||||
screen.blit(presskey_image, presskey_rect) # 绘制说明文字
|
||||
while True:
|
||||
check_mode_events(settings) # 检测键盘
|
||||
if settings.game_mode != 0: # 说明按了1或2,退出循环
|
||||
break
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
def show_end(settings, screen):
|
||||
"""失败结算界面"""
|
||||
title_font = pygame.font.Font(settings.font_name, 80)
|
||||
game_image = title_font.render('Game', True, (233, 150, 122))
|
||||
over_image = title_font.render('Over', True, (233, 150, 122))
|
||||
game_rect = game_image.get_rect()
|
||||
over_rect = over_image.get_rect()
|
||||
screen_rect = screen.get_rect()
|
||||
game_rect.midtop = (settings.width / 2, screen_rect.top + 70)
|
||||
over_rect.midtop = (settings.width / 2, game_rect.bottom + 50)
|
||||
screen.blit(game_image, game_rect)
|
||||
screen.blit(over_image, over_rect)
|
||||
pygame.display.flip()
|
||||
pygame.time.wait(1500)
|
||||
settings.game_mode = 0
|
||||
|
||||
|
||||
def draw_grid(settings, screen):
|
||||
# 绘制横向线
|
||||
for x in range(0, settings.width, settings.cell_size):
|
||||
pygame.draw.line(screen, (40, 40, 40), (x, 0), (x, settings.height))
|
||||
# 绘制竖向线
|
||||
for y in range(0, settings.height, settings.cell_size):
|
||||
pygame.draw.line(screen, (40, 40, 40), (0, y), (settings.width, y))
|
||||
|
||||
|
||||
def draw_snake(settings, screen, snake):
|
||||
# 头部用白色
|
||||
head_index = snake.coords[0]
|
||||
x = head_index['x'] * settings.cell_size
|
||||
y = head_index['y'] * settings.cell_size
|
||||
snake_head_rect = pygame.Rect(
|
||||
x, y, settings.cell_size, settings.cell_size)
|
||||
pygame.draw.rect(screen, (255, 255, 255), snake_head_rect)
|
||||
# 蛇身内部用浅绿,外框用深绿
|
||||
for bodies_index in snake.coords[1: -1]:
|
||||
x = bodies_index['x'] * settings.cell_size
|
||||
y = bodies_index['y'] * settings.cell_size
|
||||
snake_part_rect = pygame.Rect(
|
||||
x, y, settings.cell_size, settings.cell_size)
|
||||
pygame.draw.rect(screen, (0, 155, 0), snake_part_rect)
|
||||
snake_part_inner_rect = pygame.Rect(
|
||||
x + 4, y + 4, settings.cell_size - 8, settings.cell_size - 8)
|
||||
pygame.draw.rect(screen, (0, 255, 0), snake_part_inner_rect)
|
||||
# 蛇尾用浅绿
|
||||
tail_index = snake.coords[-1]
|
||||
x = tail_index['x'] * settings.cell_size
|
||||
y = tail_index['y'] * settings.cell_size
|
||||
snake_tail_rect = pygame.Rect(
|
||||
x, y, settings.cell_size, settings.cell_size)
|
||||
pygame.draw.rect(screen, (0, 255, 0), snake_tail_rect)
|
||||
|
||||
|
||||
def draw_apple(apple,settings,screen):
|
||||
x = apple.x * settings.cell_size
|
||||
y = apple.y * settings.cell_size
|
||||
apple_rect = pygame.Rect(
|
||||
x, y, settings.cell_size, settings.cell_size)
|
||||
pygame.draw.rect(screen, (255, 0, 0), apple_rect)
|
||||
|
||||
|
||||
# 绘制游戏界面
|
||||
def update_screen(settings, screen, snake,apple):
|
||||
screen.fill(settings.bg_color)
|
||||
draw_grid(settings, screen)
|
||||
draw_apple(apple,settings,screen)
|
||||
# 移动蛇
|
||||
snake.move_head() # 加蛇头
|
||||
if game_over(snake,settings):
|
||||
settings.game_mode = -1
|
||||
elif eat_apple(snake,apple):
|
||||
apple.spawn(settings)
|
||||
draw_apple(apple,settings,screen)
|
||||
else:
|
||||
del snake.coords[-1] # 去蛇尾
|
||||
draw_snake(settings, screen, snake)
|
||||
pygame.display.flip()
|
||||
# 暂停一下
|
||||
settings.my_clock.tick(settings.clock_frq)
|
||||
|
||||
|
||||
def autoupdate_screen(settings, screen, snake,apple,ai):
|
||||
screen.fill(settings.bg_color)
|
||||
draw_grid(settings, screen)
|
||||
draw_apple(apple,settings,screen)
|
||||
# 移动蛇
|
||||
snake.automove_head(ai) # 加蛇头
|
||||
if game_over(snake,settings):
|
||||
settings.game_mode = -1
|
||||
elif eat_apple(snake,apple):
|
||||
apple.spawn(settings)
|
||||
draw_apple(apple,settings,screen)
|
||||
else:
|
||||
del snake.coords[-1] # 去蛇尾
|
||||
draw_snake(settings, screen, snake)
|
||||
pygame.display.flip()
|
||||
# 暂停一下
|
||||
settings.my_clock.tick(settings.clock_frq)
|
||||
|
||||
|
||||
def game_over(snake,settings):
|
||||
# 碰到左右墙壁
|
||||
if (snake.coords[snake.head_index]['x'] == -1 or snake.coords[snake.head_index]['x'] == settings.cell_w):
|
||||
return True
|
||||
# 碰到上下墙壁
|
||||
if (snake.coords[snake.head_index]['y'] == -1 or snake.coords[snake.head_index]['y'] == settings.cell_h):
|
||||
return True
|
||||
# 碰到自己
|
||||
if (snake.coords[snake.head_index] in snake.coords[1:]):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def eat_apple(snake,apple):
|
||||
if (snake.coords[snake.head_index] == apple.coords):
|
||||
return True
|
||||
return False
|
Loading…
Reference in New Issue
Block a user