Building a Snake Game using Prompt Engineering
Building a Snake Game using Prompt Engineering
Creating a Snake Game with AI Prompt Engineering
In today’s world, artificial intelligence (AI) is revolutionizing the way we approach problem-solving and task automation. One fascinating application of AI is prompt engineering, which involves crafting human-readable instructions (prompts) to guide AI models in completing specific tasks. In this blog post, we’ll explore how we leveraged AI prompt engineering to create a classic snake game.
The Journey Begins
Our journey started with a simple idea: to build a snake game using AI prompt engineering techniques. We wanted to demonstrate the capabilities of modern AI systems in creating interactive applications while highlighting the power of well-crafted prompts.
Setting the Stage with AI Prompts
The first step was to provide the AI model with a clear and concise prompt, outlining the desired outcome and requirements for the snake game. We crafted a prompt that encompassed the game’s mechanics, such as snake movement, food collision, score tracking, and game over conditions.
Sure, here’s a complete Python code for a basic snake game with various features such as movement, collision detection, score tracking, and game over condition. This implementation uses the pygame
module for graphics and event handling:
import pygame
import random
# Initialize Pygame
pygame.init()
# Set up the game window
window_width = 800
window_height = 600
window = pygame.display.set_mode((window_width, window_height))
pygame.display.set_caption("Snake Game")
# Define colors
black = (0, 0, 0)
green = (0, 255, 0)
red = (255, 0, 0)
# Define game components
snake_position = [100, 100]
snake_body = [[100, 100], [90, 100], [80, 100]]
food_position = [random.randrange(1, (window_width // 10)) * 10, random.randrange(1, (window_height // 10)) * 10]
food_spawned = True
direction = 'RIGHT'
change_to = direction
score = 0
# Define game clock
clock = pygame.time.Clock()
# Game loop
game_over = False
while not game_over:
# Handle events
for event in pygame.event.get():
if event.type == pygame.QUIT:
game_over = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT and change_to != 'RIGHT':
change_to = 'LEFT'
elif event.key == pygame.K_RIGHT and change_to != 'LEFT':
change_to = 'RIGHT'
elif event.key == pygame.K_UP and change_to != 'DOWN':
change_to = 'UP'
elif event.key == pygame.K_DOWN and change_to != 'UP':
change_to = 'DOWN'
# Update game state
if change_to == 'LEFT' and direction != 'RIGHT':
direction = 'LEFT'
elif change_to == 'RIGHT' and direction != 'LEFT':
direction = 'RIGHT'
elif change_to == 'UP' and direction != 'DOWN':
direction = 'UP'
elif change_to == 'DOWN' and direction != 'UP':
direction = 'DOWN'
# Move the snake
if direction == 'LEFT':
snake_position[0] -= 10
elif direction == 'RIGHT':
snake_position[0] += 10
elif direction == 'UP':
snake_position[1] -= 10
elif direction == 'DOWN':
snake_position[1] += 10
# Insert the new head position at the beginning of the snake body
snake_body.insert(0, list(snake_position))
# Check for food collision
if snake_position[0] == food_position[0] and snake_position[1] == food_position[1]:
food_spawned = False
score += 10
else:
snake_body.pop()
# Spawn new food
if not food_spawned:
food_position = [random.randrange(1, (window_width // 10)) * 10, random.randrange(1, (window_height // 10)) * 10]
food_spawned = True
# Draw game elements
window.fill(black)
for position in snake_body:
pygame.draw.rect(window, green, (position[0], position[1], 10, 10))
pygame.draw.rect(window, red, (food_position[0], food_position[1], 10, 10))
pygame.display.set_caption(f"Snake Game | Score: {score}")
pygame.display.update()
# Check for collisions
for body_part in snake_body[1:]:
if snake_position[0] == body_part[0] and snake_position[1] == body_part[1]:
game_over = True
break
# Check for wall collisions
if (
snake_position[0] < 0
or snake_position[0] > window_width - 10
or snake_position[1] < 0
or snake_position[1] > window_height - 10
):
game_over = True
# Set the game speed
clock.tick(15)
# Quit Pygame
pygame.quit()
Here’s a breakdown of the code:
- The game components are initialized, including the snake’s position, body, food position, direction, score, and game clock.
- The game loop continuously runs until the
game_over
condition is met. - User input is handled through the
pygame.KEYDOWN
event, allowing the player to change the snake’s direction. - The snake’s position is updated based on the current direction.
- The snake’s body is updated by inserting the new head position at the beginning and removing the last position if the snake hasn’t eaten food.
- Food collision is checked, and if the snake eats the food, the score is incremented, and a new food position is generated.
- The game elements (snake body and food) are drawn on the window using
pygame.draw.rect
. - Collisions with the snake’s body and walls are checked, and the
game_over
condition is set accordingly. - The game speed is controlled using
clock.tick(15)
, which limits the frame rate to 15 frames per second.
This code covers the basic functionality of a snake game, including movement, collision detection, score tracking, and game over condition. You can further enhance the game by adding additional features such as sound effects, levels, high scores, and a pause/resume functionality.
The AI model, trained on vast amounts of data, interpreted our prompt and generated a Python implementation of the snake game. This initial version included the core functionality, like snake movement, food collision detection, and score tracking.
Iterative Refinement through Prompt Engineering
While the initial output was impressive, we recognized the need for further refinements and enhancements. This is where the true power of prompt engineering came into play. We iteratively refined our prompts, providing additional instructions and clarifications, guiding the AI model to improve and expand upon the initial code.
Convert this into an HTML5 and CSS3 website code.
The AI model seamlessly adapted and generated the corresponding HTML, CSS, and JavaScript code, enabling us to create a web-based snake game.
Adding Personal Touches
As we continued refining the prompts, we sought to incorporate personalized elements into the project. We asked the AI model to modify the screen size, adjust the snake’s speed, and include an introduction blurb mentioning the game’s creation using AI prompt engineering.
Make the screen size 800x600 for the game.
Reproduce the code with a reduced speed.
Include an introduction blurb indicating this game was created with AI Prompt Engineering.
The AI model dutifully implemented these changes, resulting in a customized and engaging experience for the users.
Enhancing the User Experience
To further enrich the game’s user experience, we prompted the AI model to maintain a list of high scores:
Maintain a list of high scores.
The AI model seamlessly integrated this feature, allowing players to track their progress and compete with others for the top spot on the leaderboard.
HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake Game (AI-Powered)</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<div id="game-container">
<h1>Snake Game (Created with AI Prompt Engineering)</h1>
<p id="intro">This snake game was created using AI prompt engineering techniques to demonstrate the capabilities of modern AI systems in building interactive applications.</p>
<canvas id="game-canvas"></canvas>
<div id="score-container">Score: <span id="score">0</span></div>
<div id="high-scores-container">
<h2>High Scores</h2>
<ol id="high-scores-list"></ol>
</div>
</div>
<script src="game.js"></script>
</body>
</html>
CSS (styles.css):
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background-color: #333;
font-family: Arial, sans-serif;
color: #fff;
}
#game-container {
text-align: center;
max-width: 800px;
padding: 20px;
}
#intro {
margin-bottom: 20px;
}
#game-canvas {
border: 1px solid #fff;
background-color: #000;
}
#score-container {
margin-top: 10px;
font-size: 18px;
}
#high-scores-container {
margin-top: 20px;
text-align: left;
}
#high-scores-list {
list-style-type: decimal;
padding-left: 20px;
}
JavaScript (game.js):
// Get the canvas element and its 2D rendering context
const canvas = document.getElementById('game-canvas');
const ctx = canvas.getContext('2d');
// Set the canvas dimensions
canvas.width = 800;
canvas.height = 600;
// Define game variables
let snake = [
{ x: 400, y: 300 },
{ x: 390, y: 300 },
{ x: 380, y: 300 }
];
let food = { x: 200, y: 200 };
let direction = 'right';
let score = 0;
let highScores = JSON.parse(localStorage.getItem('highScores')) || [];
// Draw the game elements
function drawGame() {
// Clear the canvas
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw the snake
ctx.fillStyle = 'green';
snake.forEach(segment => {
ctx.fillRect(segment.x, segment.y, 10, 10);
});
// Draw the food
ctx.fillStyle = 'red';
ctx.fillRect(food.x, food.y, 10, 10);
}
// Update the game state
function updateGame() {
// Move the snake
const head = { x: snake[0].x, y: snake[0].y };
switch (direction) {
case 'up':
head.y -= 10;
break;
case 'down':
head.y += 10;
break;
case 'left':
head.x -= 10;
break;
case 'right':
head.x += 10;
break;
}
snake.unshift(head);
// Check for food collision
if (head.x === food.x && head.y === food.y) {
score += 10;
document.getElementById('score').textContent = score;
food = { x: Math.floor(Math.random() * 79) * 10, y: Math.floor(Math.random() * 59) * 10 };
} else {
snake.pop();
}
// Check for collisions
if (
head.x < 0 || head.x >= canvas.width ||
head.y < 0 || head.y >= canvas.height ||
snake.slice(1).some(segment => segment.x === head.x && segment.y === head.y)
) {
gameOver();
}
}
// Handle keyboard input
document.addEventListener('keydown', event => {
const key = event.key.toLowerCase();
if (key === 'arrowup' && direction !== 'down') {
direction = 'up';
} else if (key === 'arrowdown' && direction !== 'up') {
direction = 'down';
} else if (key === 'arrowleft' && direction !== 'right') {
direction = 'left';
} else if (key === 'arrowright' && direction !== 'left') {
direction = 'right';
}
});
// Game over function
function gameOver() {
const gameOverMessage = `Game Over! Your score: ${score}`;
alert(gameOverMessage);
// Save high score
const playerName = prompt('Enter your name for the high score list:');
if (playerName) {
highScores.push({ name: playerName, score: score });
highScores.sort((a, b) => b.score - a.score);
highScores = highScores.slice(0, 10); // Keep only the top 10 scores
localStorage.setItem('highScores', JSON.stringify(highScores));
updateHighScoresList();
}
location.reload();
}
// Update the high scores list
function updateHighScoresList() {
const highScoresList = document.getElementById('high-scores-list');
highScoresList.innerHTML = '';
highScores.forEach((entry, index) => {
const listItem = document.createElement('li');
listItem.textContent = `${index + 1}. ${entry.name} - ${entry.score}`;
highScoresList.appendChild(listItem);
});
}
// Game loop
let lastFrameTime = 0;
const frameDelay = 150; // Adjust this value to control the snake's speed (higher value = slower speed)
function gameLoop(currentTime) {
const timeSinceLastFrame = currentTime - lastFrameTime;
if (timeSinceLastFrame >= frameDelay) {
lastFrameTime = currentTime;
drawGame();
updateGame();
}
requestAnimationFrame(gameLoop);
}
// Initialize the high scores list
updateHighScoresList();
// Start the game loop
gameLoop();
Here’s what has been added or modified:
HTML:
- Added an
h1
heading with the game title and a mention of “AI Prompt Engineering”. - Added a
p
element with anid="intro"
to display an introduction blurb about the game being created using AI prompt engineering. - Added a new
div
withid="high-scores-container"
to display the list of high scores. - Inside the high scores container, added an
h2
heading and an ordered list (ol
) withid="high-scores-list"
to display the high scores.
CSS:
- Added styles for the introduction blurb, high scores container, and high scores list.
JavaScript:
- Initialized an empty
highScores
array or retrieved the existing high scores fromlocalStorage
if available. - Added a
gameOver
function that handles the game over condition and prompts the player to enter their name for the high score list. - Inside the
gameOver
function, the player’s score is added to thehighScores
array, the array is sorted in descending order based on the scores, and only the top 10 scores are kept. - The
highScores
array is then saved tolocalStorage
for persistence across
Conclusion
Throughout this project, we witnessed the remarkable capabilities of AI prompt engineering in creating interactive applications. By crafting well-structured prompts and iteratively refining them, we were able to guide the AI model in generating a fully-functional snake game with various features and enhancements.
See the game in action here
This experience showcases the potential of AI prompt engineering as a powerful tool for developers, enabling them to leverage AI models for task automation, code generation, and rapid prototyping. As AI technologies continue to evolve, the possibilities for creating innovative and engaging applications through prompt engineering are truly exciting.