大家早好、午好、晚好吖 ❤ ~欢迎光临本文章
贪食蛇(也叫贪吃蛇)是一款经典的小游戏。
初始是像素版本,后来又衍生出3D版本、多人对战版本等。
今天我们就来用机器人玩一下贪吃蛇,看看最高能斩获多少分!!!
python 3.8 运行代码
pycharm 2022.3.2 辅助敲代码 专业版
音乐
字体
import cfg
import pygame
from modules.food import *
from modules.snake import *
from modules.utils import *
from modules.agent import *
from modules.endInterface import *
'''main function'''
def main(cfg):
# initialize the game
pygame.init()
screen = pygame.display.set_mode(cfg.SCREENSIZE)
pygame.display.set_caption('贪吃蛇自动版 ')
clock = pygame.time.Clock()
# play the background music
pygame.mixer.music.load(cfg.BGMPATH)
pygame.mixer.music.play(-1)
# the game main loop
snake = Snake(cfg)
ai = Agent(cfg, snake)
apple = Apple(cfg, snake.coords)
score = 0
while True:
screen.fill(cfg.BLACK)
# --check the keyboard
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
# --make decision by agent
infos = ai.act(snake, apple)
# --update the food and score
if infos and infos['eaten']:
apple = infos['food']
assert apple, 'bugs may exist'
score += 1
# --judge whether the game is over
if snake.isgameover: break
# --draw the necessary elements in the game
drawGameGrid(cfg, screen)
snake.draw(screen)
apple.draw(screen)
showScore(cfg, score, screen)
# --update the screen
pygame.display.update()
clock.tick(cfg.FPS)
return endInterface(screen, cfg)
完整源码、素材加微信: pytho8987获取,验证备注"777"
'''run'''
if __name__ == '__main__':
while True:
try:
if not main(cfg):
break
except:
continue
'''config file'''
import os
'''the resource paths'''
BGMPATH = os.path.join(os.getcwd(), 'resources/music/bgm.mp3')
FONTPATH = os.path.join(os.getcwd(), 'resources/font/Gabriola.ttf')
'''screen size'''
SCREENSIZE = (400, 400)
'''FPS'''
FPS = 30
'''some constants'''
BLOCK_SIZE = 20
BLACK = (0, 0, 0)
GAME_MATRIX_SIZE = (int(SCREENSIZE[0]/BLOCK_SIZE), int(SCREENSIZE[1]/BLOCK_SIZE))
from modules.food import *
from operator import itemgetter
from collections import OrderedDict
'''ai agent'''
class Agent():
def __init__(self, cfg, snake, **kwargs):
self.cfg = cfg
self.num_rows = cfg.GAME_MATRIX_SIZE[1]
self.num_cols = cfg.GAME_MATRIX_SIZE[0]
self.directions = [(0, -1), (0, 1), (-1, 0), (1, 0)]
self.path = self.buildcircle(snake)
self.shortcut_path = {}
'''make decision'''
def act(self, snake, food):
# make decision
if self.shortcut_path:
head_next = self.shortcut_path.pop(snake.coords[0])
else:
head_next = self.path[snake.coords[0]]
query = (head_next[0]-snake.coords[0][0], head_next[1]-snake.coords[0][1])
direction = {(-1, 0): 'left', (1, 0): 'right', (0, -1): 'up', (0, 1): 'down'}[query]
snake.setDirection(direction)
if snake.update(food):
food = Apple(self.cfg, snake.coords)
infos = {'eaten': True, 'food': food}
else:
infos = {'eaten': False, 'food': None}
# if snake has eaten the food
if head_next == food.coord:
path = self.buildcircle(snake)
if path:
self.path = path
# take shortcut
if self.shortcut_path:
return
shortcut_path = self.shortcut(snake, food)
if shortcut_path:
self.shortcut_path = shortcut_path
# return the necessary infos
return infos
'''calculate shortcut path'''
def shortcut(self, snake, food):
# empty screen, with the ordered hamitonian cycle precomputed and order numbered
world = [[0 for i in range(self.num_cols)] for j in range(self.num_rows)]
num = 1
node = snake.coords[-1]
world[node[1]][node[0]] = num
node = self.path[node]
while node != snake.coords[-1]:
num += 1
world[node[1]][node[0]] = num
node = self.path[node]
# obtain shortcut_path
wall = snake.coords
food = food.coord
food_number = world[food[1]][food[0]]
node, pre = wall[0], (-1, -1)
wait = OrderedDict()
wait[node] = pre
path = {}
while wait:
node, pre = wait.popitem(last=False)
path[node] = pre
if node == food:
break
node_number = world[node[1]][node[0]]
neigh = {}
for direction in self.directions:
to = (node[0]+direction[0], node[1]+direction[1])
if not self.checkboundary(to):
continue
if to in wait or to in wall or to in path:
continue
to_number = world[to[1]][to[0]]
if to_number > node_number and to_number <= food_number:
neigh[node_number] = to
neigh = sorted(neigh.items(), key=itemgetter(0), reverse=True)
for item in neigh:
wait[item[1]] = node
if node != food:
return {}
return self.reverse(path, snake.coords[0], food)
'''check boundary'''
def checkboundary(self, pos):
if pos[0] < 0 or pos[1] < 0 or pos[0] >= self.num_cols or pos[1] >= self.num_rows:
return False
return True
'''the shortest'''
def shortest(self, wall, head, food):
wait = OrderedDict()
node, pre = head, (-1, -1)
wait[node] = pre
path = {}
while wait:
node, pre = wait.popitem(last=False)
path[node] = pre
if node == food:
break
if pre in path:
prepre = path[pre]
direction = (pre[0]-prepre[0], pre[1]-prepre[1])
if (direction in self.directions) and (direction != self.directions[0]):
self.directions.remove(direction)
self.directions.insert(0, direction)
for direction in self.directions:
to = (node[0] + direction[0], node[1] + direction[1])
if not self.checkboundary(to):
continue
if to in path or to in wait or to in wall:
continue
wait[to] = node
if node != food:
return None
return self.reverse(path, head, food)
完整源码、素材加微信: pytho8987获取,验证备注"777"
'''reverse path'''
def reverse(self, path, head, food):
if not path: return path
path_new = {}
node = food
while node != head:
path_new[path[node]] = node
node = path[node]
return path_new
'''the longest'''
def longest(self, wall, head, food):
path = self.shortest(wall, head, food)
if path is None:
return None
node = head
while node != food:
if self.extendpath(path, node, wall+[food]):
node = head
continue
node = path[node]
return path
'''extend path'''
def extendpath(self, path, node, wall):
next_ = path[node]
direction_1 = (next_[0]-node[0], next_[1]-node[1])
if direction_1 in [(0, -1), (0, 1)]:
directions = [(-1, 0), (1, 0)]
else:
directions = [(0, -1), (0, 1)]
for d in directions:
src = (node[0]+d[0], node[1]+d[1])
to = (next_[0]+d[0], next_[1]+d[1])
if (src == to) or not (self.checkboundary(src) and self.checkboundary(to)):
continue
if src in path or src in wall or to in path or to in wall:
continue
direction_2 = (to[0]-src[0], to[1]-src[1])
if direction_1 == direction_2:
path[node] = src
path[src] = to
path[to] = next_
return True
return False
'''build a Hamiltonian cycle'''
def buildcircle(self, snake):
path = self.longest(snake.coords[1: -1], snake.coords[0], snake.coords[-1])
if (not path) or (len(path) - 1 != self.num_rows * self.num_cols - len(snake.coords)):
return None
for i in range(1, len(snake.coords)):
path[snake.coords[i]] = snake.coords[i-1]
return path
好了,今天的分享就差不多到这里了!
完整代码、更多资源、疑惑解答直接点击下方名片自取即可。
对下一篇大家想看什么,可在评论区留言哦!看到我会更新哒(ง •_•)ง
喜欢就关注一下博主,或点赞收藏评论一下我的文章叭!!!
最后,宣传一下呀~更多源码、资料、素材、解答、交流皆点击下方名片获取呀