import tkinter as tk
import random

# 游戏常量
GRID_SIZE = 20          # 网格大小（像素）
GRID_WIDTH = 30         # 横向格子数
GRID_HEIGHT = 30        # 纵向格子数
INITIAL_SPEED = 150     # 初始移动间隔（毫秒）

class SnakeGame:
    def __init__(self, master):
        self.master = master
        master.title("贪吃蛇")
        # 画布
        self.canvas = tk.Canvas(
            master,
            width=GRID_SIZE * GRID_WIDTH,
            height=GRID_SIZE * GRID_HEIGHT,
            bg="black"
        )
        self.canvas.pack()

        # 得分标签
        self.score_label = tk.Label(master, text="得分: 0", font=("Arial", 16))
        self.score_label.pack()

        # 初始化游戏状态
        self.reset_game()

        # 绑定方向键
        master.bind("<Up>", lambda e: self.change_direction("up"))
        master.bind("<Down>", lambda e: self.change_direction("down"))
        master.bind("<Left>", lambda e: self.change_direction("left"))
        master.bind("<Right>", lambda e: self.change_direction("right"))
        # 空格键重新开始
        master.bind("<space>", lambda e: self.reset_game())

        # 开始游戏循环
        self.game_loop()

    def reset_game(self):
        """重置游戏到初始状态"""
        # 蛇的初始位置：中部，长度为3，向右移动
        self.snake = [
            (GRID_WIDTH // 2, GRID_HEIGHT // 2),
            (GRID_WIDTH // 2 - 1, GRID_HEIGHT // 2),
            (GRID_WIDTH // 2 - 2, GRID_HEIGHT // 2)
        ]
        self.direction = "right"      # 当前移动方向
        self.next_direction = "right" # 下一次移动实际方向
        self.food = None
        self.score = 0
        self.game_over = False
        self.speed = INITIAL_SPEED
        self.score_label.config(text="得分: 0")
        self.draw()

    def change_direction(self, new_dir):
        """改变蛇的移动方向（防止直接反向）"""
        opposites = {"up": "down", "down": "up", "left": "right", "right": "left"}
        if new_dir != opposites.get(self.direction):
            self.next_direction = new_dir

    def move_snake(self):
        """根据当前方向移动蛇，返回是否吃到食物"""
        head = self.snake[0]
        x, y = head
        if self.direction == "up":
            y -= 1
        elif self.direction == "down":
            y += 1
        elif self.direction == "left":
            x -= 1
        elif self.direction == "right":
            x += 1

        new_head = (x, y)

        # 检查是否吃到食物
        ate_food = (new_head == self.food)

        # 插入新头部
        self.snake.insert(0, new_head)

        if not ate_food:
            # 没吃到就移除尾部
            self.snake.pop()
        else:
            # 吃到食物：分数增加，生成新食物，加速（可选）
            self.score += 1
            self.score_label.config(text=f"得分: {self.score}")
            self.generate_food()
            # 速度逐渐加快，但不超过一定值
            if self.speed > 50:
                self.speed -= 2

        return ate_food

    def generate_food(self):
        """在空白位置随机生成食物"""
        # 获取所有蛇身占用的格子
        occupied = set(self.snake)
        # 所有可能的位置
        all_positions = [(x, y) for x in range(GRID_WIDTH) for y in range(GRID_HEIGHT)]
        available = [pos for pos in all_positions if pos not in occupied]
        if available:
            self.food = random.choice(available)
        else:
            # 所有格子被蛇填满，玩家胜利（视为游戏结束）
            self.game_over = True

    def check_collision(self):
        """检测是否撞墙或撞自身"""
        head = self.snake[0]
        x, y = head
        # 撞墙
        if x < 0 or x >= GRID_WIDTH or y < 0 or y >= GRID_HEIGHT:
            return True
        # 撞自身（头部与后面身体重叠，但头部本身不检测）
        if head in self.snake[1:]:
            return True
        return False

    def draw(self):
        """绘制当前游戏状态"""
        self.canvas.delete("all")

        # 绘制蛇
        for i, (x, y) in enumerate(self.snake):
            color = "lime" if i == 0 else "green"
            self.canvas.create_rectangle(
                x * GRID_SIZE, y * GRID_SIZE,
                (x + 1) * GRID_SIZE, (y + 1) * GRID_SIZE,
                fill=color, outline="darkgreen"
            )

        # 绘制食物
        if self.food:
            fx, fy = self.food
            self.canvas.create_oval(
                fx * GRID_SIZE, fy * GRID_SIZE,
                (fx + 1) * GRID_SIZE, (fy + 1) * GRID_SIZE,
                fill="red", outline="darkred"
            )

        # 游戏结束显示文字
        if self.game_over:
            self.canvas.create_text(
                GRID_SIZE * GRID_WIDTH // 2,
                GRID_SIZE * GRID_HEIGHT // 2,
                text="游戏结束！\n按空格重新开始",
                fill="white",
                font=("Arial", 24, "bold"),
                justify="center"
            )

    def game_loop(self):
        """主循环：更新游戏状态并定时调用自身"""
        if not self.game_over:
            # 更新方向
            self.direction = self.next_direction

            # 移动蛇
            ate = self.move_snake()

            # 碰撞检测
            if self.check_collision():
                self.game_over = True

            # 如果食物还未生成（初始时），生成第一个食物
            if self.food is None and not self.game_over:
                self.generate_food()
                # 如果生成食物时 game_over 变为 True（所有格子被占），则结束
                if self.game_over:
                    self.draw()
                    self.master.after(self.speed, self.game_loop)
                    return

            # 重绘
            self.draw()

        # 继续循环（即使游戏结束也要继续调用，以便可以按空格重置）
        self.master.after(self.speed, self.game_loop)

if __name__ == "__main__":
    root = tk.Tk()
    game = SnakeGame(root)
    root.mainloop()