python贪吃蛇游戏项目-修改贪吃蛇项目(多个奖励且修改食物样式)

import pygame
import time
import random
import numpy as np
from dataclasses import dataclass

'''
可以建立自定义的字串蛇蛇.
'''

@dataclass
class snake():
    pygame.font.init()
    # 游戏窗口大小和速度设置
    window_width = 800
    window_height = 600
    snake_block = 10
    snake_speed = 15
    
    # 定义颜色
    black = (0, 0, 0)
    white = (255, 255, 255)
    purple = (155, 89, 182)
    carrot = (230, 126, 34)
    green = (46, 204, 113)
    blue = (52, 152, 219)

    game_window = None
    snake_list = []
    snake_length = 1
    snake_x = window_width / 2
    snake_y = window_height / 2
    snake_x_change = 0
    snake_y_change = 0
    food_x1 = None
    food_y1 = None
    food_x2 = None
    food_y2 = None
    food_x3 = None
    food_y3 = None
    food_font = pygame.font.SysFont(None, 20)
    clock = pygame.time.Clock()
    action = None

    def _init_windows(self):
        # 创建游戏窗口
        self.game_window = pygame.display.set_mode((self.window_width, self.window_height))
        pygame.display.set_caption('贪吃蛇游戏')

    def design_snake(self, snake_block, snake_list):
        for x in snake_list:
            pygame.draw.rect(self.game_window, self.green, [x[0], x[1], snake_block, snake_block])

    def design_food1(self):
        text = self.food_font.render("P", True, self.purple)
        self.game_window.blit(text, (self.food_x1, self.food_y1))

    def design_food2(self):
        text = self.food_font.render("P", True, self.carrot)
        self.game_window.blit(text, (self.food_x2, self.food_y2))

    def design_food3(self):
        text = self.food_font.render("P", True, self.green)
        self.game_window.blit(text, (self.food_x3, self.food_y3))

    def display_score(self, score):
        font = pygame.font.SysFont(None, 15)
        text = font.render(str(score), True, self.blue)
        self.game_window.blit(text, [10, 10])
    
    def score_table_show(self):
        # 显示游戏结束信息
        font_style = pygame.font.SysFont(None, 15)
        message = font_style.render(str(self.snake_length - 1), True, self.black)
        self.game_window.blit(message, [self.window_width / 2, self.window_height / 2])
        pygame.display.update()
        time.sleep(2)  # 等待2秒后退出游戏

    def reset(self):
        self._init_windows()
        self.snake_list = []
        self.snake_length = 1
        self.snake_x = self.window_width / 2
        self.snake_y = self.window_height / 2
        self.snake_x_change = 0
        self.snake_y_change = 0
        self.food_x1 = round(random.randrange(0, self.window_width - self.snake_block) / 20.0) * 20.0
        self.food_y1 = round(random.randrange(0, self.window_height - self.snake_block) / 20.0) * 20.0
        self.food_x2 = round(random.randrange(0, self.window_width - self.snake_block) / 20.0) * 20.0
        self.food_y2 = round(random.randrange(0, self.window_height - self.snake_block) / 20.0) * 20.0
        self.food_x3 = round(random.randrange(0, self.window_width - self.snake_block) / 20.0) * 20.0
        self.food_y3 = round(random.randrange(0, self.window_height - self.snake_block) / 20.0) * 20.0

        observation = self.get_observation()
        return observation

    def step(self,action):
        if action == 0:
            self.snake_y_change = -self.snake_block
            self.snake_x_change = 0
        elif action == 1:
            self.snake_y_change = self.snake_block
            self.snake_x_change = 0
        elif action == 2:
            self.snake_x_change = -self.snake_block
            self.snake_y_change = 0
        elif action == 3:
            self.snake_x_change = self.snake_block
            self.snake_y_change = 0

        self.snake_x += self.snake_x_change
        self.snake_y += self.snake_y_change

        done = False
        reward = 0

        if self.snake_x >= self.window_width or self.snake_x < 0 or self.snake_y >= self.window_height or self.snake_y < 0:
            self.score_table_show()
            reward = -10
            done = True

        if [self.snake_x, self.snake_y] in self.snake_list[:-1]:
            self.score_table_show()
            reward = -10
            done = True

        self.game_window.fill(self.white)
        self.design_food1()
        self.design_food2()
        self.design_food3()
        snake_head = []
        snake_head.append(self.snake_x)
        snake_head.append(self.snake_y)
        self.snake_list.append(snake_head)
        if len(self.snake_list) > self.snake_length:
            del self.snake_list[0]

        self.design_snake(self.snake_block, self.snake_list)
        self.display_score(self.snake_length - 1)
        pygame.display.update()

        if self.snake_x == self.food_x1 and self.snake_y == self.food_y1:
            self.food_x1 = round(random.randrange(0, self.window_width - self.snake_block) / 20.0) * 20.0
            self.food_y1 = round(random.randrange(0, self.window_height - self.snake_block) / 20.0) * 20.0
            self.snake_length += 1
            reward = 10

        if self.snake_x == self.food_x2 and self.snake_y == self.food_y2:
            self.food_x2 = round(random.randrange(0, self.window_width - self.snake_block) / 20.0) * 20.0
            self.food_y2 = round(random.randrange(0, self.window_height - self.snake_block) / 20.0) * 20.0
            self.snake_length += 1
            reward = 10
        
        if self.snake_x == self.food_x3 and self.snake_y == self.food_y3:
            self.food_x3 = round(random.randrange(0, self.window_width - self.snake_block) / 20.0) * 20.0
            self.food_y3 = round(random.randrange(0, self.window_height - self.snake_block) / 20.0) * 20.0
            self.snake_length += 1
            reward = 10

        observation = self.get_observation()
        return observation, reward, done, {}

    def get_observation(self):
        observation = pygame.surfarray.array3d(pygame.display.get_surface())
        observation = np.transpose(observation, axes=(1, 0, 2))
        return observation

    def render(self, mode=None):
        # 在屏幕上显示游戏状态
        self.game_window.fill(self.white)
        self.design_food1()
        self.design_food2()
        self.design_food3()
        self.design_snake(self.snake_block, self.snake_list)
        self.display_score(self.snake_length - 1)
        pygame.display.update()
        self.clock.tick(self.snake_speed)
        
        if mode in ('human','h') :
            # 等待玩家操作
            for event in pygame.event.get():
                if event.type == pygame.KEYDOWN :
                    if event.key == pygame.K_UP:
                        return 0 
                    elif event.key == pygame.K_DOWN:
                        return 1
                    elif event.key == pygame.K_LEFT:
                        return 2
                    elif event.key == pygame.K_RIGHT:
                        return 3

    def close(self):
        pygame.quit()
        quit()
    
    def run(self):
        action = env.render(mode='h')  #人类模式下,玩家通过键盘操作
        if action != None :
            print(action)
        return self.step(action)

if __name__ == "__main__":

    env = snake()
    observation = env.reset()
    done = False

    while not done:
        observation, reward, done, _ = env.run()