โ
Game Snake โ
๐ฆ Game code, download & prompt info
๐ฅ๏ธ Desktop app (python) โ play it live above, right in your browser, or download it below
Original prompt
Write a complete, runnable Python program using `pygame` that implements a playable Snake game. Open a window, draw a grid, a snake that grows by one segment when it eats food, and control direction with the arrow keys. The game ends when the snake hits the wall or itself. Display the current length/score. Include a game loop that handles the QUIT event. Use only primitive shapes - no external assets. Design note (interpret freely): Snake became a global obsession as the bundled Nokia phone game - a minimalist grow-vs-avoid loop where the snake glides across a grid at a fixed speed, grows with every food item, and dies on the wall or its own body. Faithfully capture that tight, escalating survival tension. SCORING & PERSISTENT HIGH-SCORE BOARD (REQUIRED): The game MUST award points for gameplay actions and maintain a persistent high-score table. When a run finishes, prompt the player to enter their name/initials and record it with the score. Save the top 5 scores (name + score) to a local JSON file in the working directory (e.g. high_scores.json), and also write the latest finished run as {"initials": name, "score": number} to /tmp/alpaca_score.json (overwrite it every run) so the arcade scoreboard can pick it up automatically, load and display them on startup and on the game-over screen, and write a new entry whenever a run finishes. Scores must survive restarting the program. Every new game MUST start with the score reset to 0 - never carry over the previous game's score into the next session. The program must run top-to-bottom and open a visible window. OUTPUT REQUIREMENT: Respond with ONLY the raw, runnable source code in a single fenced code block, with the first line starting at column 0 (no leading indentation). Do not include any thinking, explanation, summary, or prose before or after the code, and keep comments inside the code minimal.import json
import os
import random
from pathlib import Path
import pygame
CELL = 24
COLS, ROWS = 26, 22
HEADER = 76
WIDTH, HEIGHT = COLS * CELL, HEADER + ROWS * CELL
STEP_TIME = 0.105
SCORE_FILE = Path.cwd() / "high_scores.json"
LATEST_FILE = Path("/tmp/alpaca_score.json")
BG = (168, 190, 118)
GRID = (151, 175, 104)
INK = (34, 53, 30)
BODY = (55, 79, 38)
PANEL = (190, 208, 150)
MUTED = (82, 106, 57)
DIRECTIONS = {
pygame.K_UP: (0, -1),
pygame.K_DOWN: (0, 1),
pygame.K_LEFT: (-1, 0),
pygame.K_RIGHT: (1, 0),
}
def load_scores():
try:
with SCORE_FILE.open("r", encoding="utf-8") as handle:
data = json.load(handle)
if not isinstance(data, list):
return []
entries = []
for entry in data:
if not isinstance(entry, dict):
continue
name = entry.get("initials")
score = entry.get("score")
if isinstance(name, str) and type(score) is int and score >= 0:
entries.append({
"initials": name.strip()[:12] or "ANON",
"score": score,
})
return sorted(entries, key=lambda item: item["score"], reverse=True)[:5]
except (OSError, ValueError):
return []
def write_json(path, data):
temporary = path.with_name(path.name + ".tmp")
with temporary.open("w", encoding="utf-8") as handle:
json.dump(data, handle, indent=2)
handle.write("\n")
os.replace(temporary, path)
class SnakeGame:
def __init__(self):
pygame.init()
pygame.display.set_caption("Snake โข Pocket Arcade")
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
self.clock = pygame.time.Clock()
self.font = pygame.font.Font(None, 28)
self.small = pygame.font.Font(None, 22)
self.large = pygame.font.Font(None, 54)
self.high_scores = load_scores()
self.state = "menu"
self.running = True
self.snake = [(12, 11), (11, 11), (10, 11)]
self.food = (18, 11)
self.score = 0
self.initials = ""
self.saved = False
self.save_message = ""
self.result = ""
def text(self, message, position, font=None, color=INK, center=False):
image = (font or self.font).render(message, True, color)
rect = image.get_rect()
if center:
rect.center = position
else:
rect.topleft = position
self.screen.blit(image, rect)
def new_game(self):
self.snake = [(COLS // 2, ROWS // 2),
(COLS // 2 - 1, ROWS // 2),
(COLS // 2 - 2, ROWS // 2)]
self.direction = (1, 0)
self.turns = []
self.elapsed = 0.0
self.score = 0
self.initials = ""
self.saved = False
self.save_message = ""
self.result = ""
self.state = "playing"
self.place_food()
def place_food(self):
occupied = set(self.snake)
empty = [(x, y) for y in range(ROWS) for x in range(COLS)
if (x, y) not in occupied]
self.food = random.choice(empty) if empty else None
def finish(self, result):
self.result = result
self.state = "entry"
self.elapsed = 0.0
self.turns.clear()
self.initials = ""
def record_run(self):
if self.saved:
return
entry = {
"initials": self.initials.strip()[:12] or "ANON",
"score": self.score,
}
self.high_scores.append(entry)
self.high_scores.sort(key=lambda item: item["score"], reverse=True)
self.high_scores = self.high_scores[:5]
errors = []
for path, data in (
(SCORE_FILE, self.high_scores),
(LATEST_FILE, entry),
):
try:
write_json(path, data)
except OSError as error:
errors.append(path.name)
print(f"Could not save {path}: {error}")
self.save_message = (
"Save failed: " + ", ".join(errors)
if errors else "Score saved."
)
self.saved = True
self.state = "gameover"
def queue_turn(self, direction):
previous = self.turns[-1] if self.turns else self.direction
if (len(self.turns) < 2 and direction != previous
and direction != (-previous[0], -previous[1])):
self.turns.append(direction)
def step(self):
if self.turns:
self.direction = self.turns.pop(0)
dx, dy = self.direction
head = (self.snake[0][0] + dx, self.snake[0][1] + dy)
eating = head == self.food
occupied = self.snake if eating else self.snake[:-1]
if not (0 <= head[0] < COLS and 0 <= head[1] < ROWS):
self.finish("You hit the wall!")
return
if head in occupied:
self.finish("You hit your own tail!")
return
self.snake.insert(0, head)
if eating:
self.score += 10
self.place_food()
if self.food is None:
self.finish("Perfect run! Grid cleared.")
else:
self.snake.pop()
def handle_events(self):
for event in pygame.event.get():
if event.type == pygame.QUIT:
if self.state == "entry":
self.record_run()
self.running = False
return
if event.type != pygame.KEYDOWN:
continue
if self.state == "playing":
if event.key in DIRECTIONS:
self.queue_turn(DIRECTIONS[event.key])
elif self.state == "entry":
if event.key == pygame.K_RETURN:
self.record_run()
elif event.key == pygame.K_BACKSPACE:
self.initials = self.initials[:-1]
elif len(self.initials) < 12:
character = event.unicode
if character and character.isascii() and (
character.isalnum() or character in " -_"
):
self.initials += character.upper()
elif self.state in ("menu", "gameover"):
if event.key in (pygame.K_RETURN, pygame.K_SPACE):
self.new_game()
elif event.key == pygame.K_ESCAPE:
self.running = False
return
def draw_board(self):
self.screen.fill(BG)
pygame.draw.rect(self.screen, INK, (0, 0, WIDTH, HEADER))
self.text("SNAKE", (18, 13), color=PANEL)
self.text(f"SCORE {self.score:04d}", (180, 13), color=PANEL)
self.text(f"LENGTH {len(self.snake)}", (390, 13), color=PANEL)
best = self.high_scores[0]["score"] if self.high_scores else 0
self.text(f"BEST {best} | ARROWS TO STEER | +10 / FOOD",
(18, 46), font=self.small, color=BG)
for x in range(COLS + 1):
pygame.draw.line(self.screen, GRID,
(x * CELL, HEADER), (x * CELL, HEIGHT))
for y in range(ROWS + 1):
pygame.draw.line(self.screen, GRID,
(0, HEADER + y * CELL),
(WIDTH, HEADER + y * CELL))
if self.food is not None:
x, y = self.food
center = (x * CELL + CELL // 2,
HEADER + y * CELL + CELL // 2)
pygame.draw.circle(self.screen, INK, center, 8)
pygame.draw.rect(self.screen, BG,
(center[0] - 2, center[1] - 2, 4, 4))
for index, (x, y) in enumerate(self.snake):
rect = pygame.Rect(x * CELL + 2, HEADER + y * CELL + 2,
CELL - 4, CELL - 4)
pygame.draw.rect(self.screen, INK if index == 0 else BODY, rect)
if index == 0:
dx, dy = getattr(self, "direction", (1, 0))
cx, cy = rect.center
for side in (-1, 1):
eye = (cx + dx * 5 - dy * side * 4,
cy + dy * 5 + dx * side * 4)
pygame.draw.circle(self.screen, PANEL, eye, 2)
def draw_scores(self, top):
self.text("TOP 5 โข HIGH SCORES", (WIDTH // 2, top),
center=True)
for index in range(5):
y = top + 32 + index * 28
if index < len(self.high_scores):
entry = self.high_scores[index]
name, score = entry["initials"], str(entry["score"])
else:
name, score = "---", "---"
self.text(f"{index + 1}. {name}", (118, y), font=self.small)
image = self.small.render(score, True, INK)
self.screen.blit(image, (WIDTH - 118 - image.get_width(), y))
def draw_overlay(self):
rect = pygame.Rect(64, HEADER + 24, WIDTH - 128, ROWS * CELL - 48)
pygame.draw.rect(self.screen, PANEL, rect)
pygame.draw.rect(self.screen, INK, rect, 3)
cx = WIDTH // 2
top = rect.top
if self.state == "menu":
self.text("SNAKE", (cx, top + 43), self.large, center=True)
self.text("Eat. Grow. Stay alive.", (cx, top + 88), center=True)
self.text("Arrow keys steer. Walls and body are fatal.",
(cx, top + 122), self.small, center=True)
self.draw_scores(top + 168)
self.text("ENTER / SPACE to start", (cx, top + 389), center=True)
self.text("ESC to quit", (cx, top + 425), self.small, center=True)
else:
title = "GRID CLEARED!" if self.food is None else "GAME OVER"
self.text(title, (cx, top + 38), self.large, center=True)
self.text(self.result, (cx, top + 77), self.small, center=True)
self.text(f"Score: {self.score} Length: {len(self.snake)}",
(cx, top + 111), center=True)
if self.state == "entry":
self.text("Enter name / initials, then press ENTER:",
(cx, top + 147), self.small, center=True)
field = pygame.Rect(150, top + 165, WIDTH - 300, 37)
pygame.draw.rect(self.screen, BG, field)
pygame.draw.rect(self.screen, INK, field, 2)
cursor = "_" if pygame.time.get_ticks() % 1000 < 500 else ""
self.text(self.initials + cursor, field.center, center=True)
else:
self.text(self.save_message, (cx, top + 164),
self.small, center=True)
self.draw_scores(top + 233)
if self.state == "entry":
footer = "Blank name saves as ANON."
else:
footer = "ENTER: play again | ESC: quit"
self.text(footer, (cx, top + 440), self.small, center=True)
def run(self):
while self.running:
dt = min(self.clock.tick(60) / 1000.0, 0.25)
self.handle_events()
if not self.running:
break
if self.state == "playing":
self.elapsed += dt
while self.elapsed >= STEP_TIME and self.state == "playing":
self.elapsed -= STEP_TIME
self.step()
self.draw_board()
if self.state != "playing":
self.draw_overlay()
pygame.display.flip()
pygame.quit()
if __name__ == "__main__":
SnakeGame().run()
๐ฎ Press โถ Play above to run it live in your browser, or download it below and run locally (pip install pygame), then enter your score by hand