上传文件至 /

搓了一个充满bug的算法框架
This commit is contained in:
Billts_noo 2024-08-14 12:30:17 +08:00
parent 9a01b8eb29
commit 4738b5c4ff
5 changed files with 347 additions and 179 deletions

84
ai.py Normal file
View 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)

View File

@ -3,9 +3,9 @@ import random
class Apple(): class Apple():
def __init__(self,settings): def __init__(self,settings):
self.x = random.randint(1, settings.cell_w - 1) self.x = 7#random.randint(1, settings.cell_w - 1)
self.y = random.randint(1, settings.cell_h - 1) self.y = 5#random.randint(1, settings.cell_h - 1)
self.coords = {'x':self.x,'y':self.y}
def spawn(self,settings): def spawn(self,settings):
self.x = random.randint(1, settings.cell_w - 1) self.x = random.randint(1, settings.cell_w - 1)
self.y = random.randint(1, settings.cell_h - 1) self.y = random.randint(1, settings.cell_h - 1)

53
data_structure.py Normal file
View 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)

View File

@ -1,8 +1,8 @@
import pygame import pygame
import sys import sys
#函数名含义check events for mode (selecting),下同
def check_events(settings): def check_mode_events(settings):
for event in pygame.event.get(): for event in pygame.event.get():
# 当按关闭或者按ESC键退出游戏 # 当按关闭或者按ESC键退出游戏
if event.type == pygame.QUIT: if event.type == pygame.QUIT:
@ -44,6 +44,18 @@ def check_play_events(snake):
break 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): def show_start(settings, screen):
"""模式选择界面""" """模式选择界面"""
title_Font = pygame.font.Font(settings.font_name, 80) # 设置标题字体 title_Font = pygame.font.Font(settings.font_name, 80) # 设置标题字体
@ -62,7 +74,7 @@ def show_start(settings, screen):
screen.blit(title_image, title_rect) # 绘制标题 screen.blit(title_image, title_rect) # 绘制标题
screen.blit(presskey_image, presskey_rect) # 绘制说明文字 screen.blit(presskey_image, presskey_rect) # 绘制说明文字
while True: while True:
check_events(settings) # 检测键盘 check_mode_events(settings) # 检测键盘
if settings.game_mode != 0: # 说明按了1或2退出循环 if settings.game_mode != 0: # 说明按了1或2退出循环
break break
pygame.display.flip() pygame.display.flip()
@ -149,6 +161,25 @@ def update_screen(settings, screen, snake,apple):
settings.my_clock.tick(settings.clock_frq) 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): def game_over(snake,settings):
# 碰到左右墙壁 # 碰到左右墙壁
if (snake.coords[snake.head_index]['x'] == -1 or snake.coords[snake.head_index]['x'] == settings.cell_w): if (snake.coords[snake.head_index]['x'] == -1 or snake.coords[snake.head_index]['x'] == settings.cell_w):
@ -163,6 +194,6 @@ def game_over(snake,settings):
def eat_apple(snake,apple): def eat_apple(snake,apple):
if (snake.coords[snake.head_index]['x'] == apple.x and snake.coords[snake.head_index]['y'] == apple.y): if (snake.coords[snake.head_index] == apple.coords):
return True return True
return False return False