"""用 Python 标准库 turtle 演示贪吃蛇;方向键移动、空格暂停、R 重开。""" import random import turtle SIZE = 20 CELL = 24 DELAY = 145 screen = turtle.Screen() screen.setup(540, 600) screen.title("Learn2Python · 贪吃蛇") screen.bgcolor("#123c35") screen.tracer(0) pen = turtle.Turtle(visible=False) pen.penup() pen.speed(0) snake = [] direction = (1, 0) pending = (1, 0) food = None score = 0 paused = False over = False turn_queued = False def new_food(): """只从空格中挑果子,棋盘填满后返回 None。""" empty = [(x, y) for y in range(SIZE) for x in range(SIZE) if (x, y) not in snake] return random.choice(empty) if empty else None def draw(): """在窗口重画蛇、果子和当前状态。""" pen.clear() for i, (x, y) in enumerate(snake): pen.goto((x - SIZE / 2) * CELL + CELL / 2, (SIZE / 2 - y) * CELL - CELL / 2) pen.dot(CELL - 3, "#e2ed8a" if i == 0 else "#b8d76e") if food is not None: x, y = food pen.goto((x - SIZE / 2) * CELL + CELL / 2, (SIZE / 2 - y) * CELL - CELL / 2) pen.dot(15, "#ffb17b") pen.goto(0, 254) pen.color("#f7f7ef") state = "GAME OVER / R to restart" if over else "PAUSED" if paused else "Arrows to move / Space to pause" pen.write(f"Score: {score} {state}", align="center", font=("Arial", 11, "normal")) screen.update() def reset(): """只重置状态,保留唯一的定时循环,防止重开后速度叠加。""" global snake, direction, pending, food, score, paused, over, turn_queued snake = [(7, 10), (6, 10), (5, 10)] direction = pending = (1, 0) score = 0 paused = over = turn_queued = False food = new_food() draw() def turn(dx, dy): """每步最多接受一次转向,并拒绝直接掉头。""" global pending, turn_queued if paused or over or turn_queued: return if (dx, dy) in (direction, (-direction[0], -direction[1])): return pending = (dx, dy) turn_queued = True def toggle_pause(): """在游戏进行中切换暂停状态。""" global paused if not over: paused = not paused draw() def tick(): """先检查碰撞再移动;每次只预约一个后续回调。""" global direction, turn_queued, food, score, over if not paused and not over: direction = pending turn_queued = False head = (snake[0][0] + direction[0], snake[0][1] + direction[1]) eating = head == food body = snake if eating else snake[:-1] if not all(0 <= n < SIZE for n in head) or head in body: over = True else: snake.insert(0, head) if eating: score += 1 food = new_food() over = food is None else: snake.pop() draw() screen.ontimer(tick, DELAY) screen.onkey(lambda: turn(0, -1), "Up") screen.onkey(lambda: turn(0, 1), "Down") screen.onkey(lambda: turn(-1, 0), "Left") screen.onkey(lambda: turn(1, 0), "Right") screen.onkey(toggle_pause, "space") screen.onkey(reset, "r") screen.onkey(reset, "R") screen.listen() reset() screen.ontimer(tick, DELAY) screen.mainloop()