Let's make a game - with AI!
Let's put Claude Sonnet 3.5 Large Language Model to a coding test, by trying to create a puzzle game with it.
The initial version of the game
We start by giving Claude Sonnet 3.5 (Link to Claude.ai), a fairly simple prompt:
Using Python, make a puzzle game involving 2D objects that can be rotated and moved. The game should have a clear goal that a human understands. The gameplay should be by keyboard only. The game quality should be very good.
This gives us a Python code that uses Pygame to implement the game:
import pygame
import sys
import math
from pygame.math import Vector2
# Initialize Pygame
pygame.init()
# Set up the display
WIDTH, HEIGHT = 800, 600
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Shape Sorter")
# Colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
# Shapes
shapes = [
{"type": "triangle", "color": RED, "points": [(0, -25), (25, 25), (-25, 25)]},
{"type": "square", "color": GREEN, "points": [(-25, -25), (25, -25), (25, 25), (-25, 25)]},
{"type": "circle", "color": BLUE, "radius": 25},
]
# Slots
slots = [
{"type": "triangle", "pos": (200, 300)},
{"type": "square", "pos": (400, 300)},
{"type": "circle", "pos": (600, 300)},
]
# Game state
current_shape = 0
shape_pos = Vector2(WIDTH // 2, HEIGHT - 100)
shape_angle = 0
game_won = False
start_time = None
# Font
font = pygame.font.Font(None, 36)
def rotate_point(point, angle):
x, y = point
return (
x * math.cos(angle) - y * math.sin(angle),
x * math.sin(angle) + y * math.cos(angle)
)
def draw_shape(shape, pos, angle):
if shape["type"] == "circle":
pygame.draw.circle(screen, shape["color"], pos, shape["radius"])
else:
rotated_points = [rotate_point(p, angle) for p in shape["points"]]
translated_points = [(p[0] + pos[0], p[1] + pos[1]) for p in rotated_points]
pygame.draw.polygon(screen, shape["color"], translated_points)
def draw_slot(slot):
pygame.draw.circle(screen, BLACK, slot["pos"], 30, 2)
def check_win():
for shape, slot in zip(shapes, slots):
if Vector2(slot["pos"]).distance_to(shape_pos) > 5:
return False
return True
# Main game loop
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if not game_won:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
shape_pos.x -= 2
if keys[pygame.K_RIGHT]:
shape_pos.x += 2
if keys[pygame.K_UP]:
shape_pos.y -= 2
if keys[pygame.K_DOWN]:
shape_pos.y += 2
if keys[pygame.K_r]:
shape_angle += 0.05
if keys[pygame.K_SPACE]:
current_shape = (current_shape + 1) % len(shapes)
if start_time is None:
start_time = pygame.time.get_ticks()
game_won = check_win()
screen.fill(WHITE)
# Draw slots
for slot in slots:
draw_slot(slot)
# Draw current shape
draw_shape(shapes[current_shape], shape_pos, shape_angle)
# Draw instructions
instructions = font.render("Arrow keys: Move, R: Rotate, Space: Next shape", True, BLACK)
screen.blit(instructions, (10, 10))
if game_won:
end_time = pygame.time.get_ticks()
time_taken = (end_time - start_time) / 1000 # Convert to seconds
win_text = font.render(f"You won! Time: {time_taken:.2f} seconds", True, BLACK)
screen.blit(win_text, (WIDTH // 2 - win_text.get_width() // 2, HEIGHT // 2))
pygame.display.flip()
clock.tick(60)
Claude also provides us some instructions, that the controls for the game are as follows:
Arrow keys to move the current shape
'R' key to rotate the shape
Spacebar to switch between shapes
Playing the game for the first time
When you run the game, you actually do get something that looks like a game. See the image below. We can also see that Claude gave the game name ‘Shape Sorter’.
When playing the game, I immediately notice some flaws with it. You can move the red triangle with your arrow keys, as expected, but changing the shape with space is way too fast. If you press the space bar down, the game goes through three shapes really fast, and I can’t really get the shape I want because of that. Also, as can be seen in the image, there are three slots, and they are all circles! Not very engaging gameplay. The third problem was that, even when I somehow managed to change the shape to a circle, and then moved it over one of the shapes, nothing happened. So the game gives us no feedback at all.
Fixing the game
Let’s try to fix the game by telling Claude of the problems with this prompt:
There are some problems with the game: All slots are circles. Nothing happens when you move the correct shape to a slot that resembles it. When you press space, the shapes are switched too quickly. It should switch one at a time, per press.
Claude then prints out another version of the game code, with the requested fixes. To make this post shorter, I won’t list the code here, but the fixes were pretty much as requested.
Above is an image of the second version. The slots are now all different shapes, and when I move the red shape on top of the triangle slot, the shape snaps in to, just the way I wanted it to (even when I didn’t request the snap). But after that, nothing happened. I would like to get another shape to be able to move it to it’s correct place. So let’s ask Claude for it.
Now create a new shape to move, once the current one has been moved to its correct slot. Also when all slots are filled, give some kind of win indication.
Claude does what I ask. The third version generates a new shape to move once the current one has been moved over the correct slot. The game also indicates which slot has already been filled, with a small yellow dot. But, Claude made a bug! I cannot change the shape with space anymore, so I still cannot finish the game. Let’s ask for a fix.
I can't change the shape anymore with space
The fourth version almost works all the way through. I can now fill all the slots with correct shapes, and I get a win screen.
You can’t see it in this image, but there’s still one bug. The timer that is shown only in the win screen, keeps on counting, even when the game clearly has been finished.
Working game
One more request to Claude:
In the win screen, the game time is still running. It should stop.
This fifth version works as you would expect. You can fill all the shapes, and you can see the time it took you to finish the game.
The code I ended up was this as follows.
# Main game loop
clock = pygame.time.Clock()
space_pressed = False
end_time = None
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
space_pressed = False
keys = pygame.key.get_pressed()
if not game_won:
if keys[pygame.K_LEFT]:
shape_pos.x -= 2
if keys[pygame.K_RIGHT]:
shape_pos.x += 2
if keys[pygame.K_UP]:
shape_pos.y -= 2
if keys[pygame.K_DOWN]:
shape_pos.y += 2
if keys[pygame.K_r]:
shape_angle += 0.05
if keys[pygame.K_SPACE] and not space_pressed:
current_shape_index = (current_shape_index + 1) % len(shapes)
space_pressed = True
if start_time is None:
start_time = pygame.time.get_ticks()
# Check if shape is in correct slot
current_shape = shapes[current_shape_index]
for slot in slots:
if check_shape_in_slot(current_shape, slot):
slot["filled"] = True
shapes.pop(current_shape_index)
if shapes:
current_shape_index = current_shape_index % len(shapes)
else:
game_won = True
end_time = pygame.time.get_ticks() # Set end_time when game is won
shape_pos = Vector2(WIDTH // 2, HEIGHT - 100)
shape_angle = 0
break
if not game_won:
game_won = check_win()
if game_won:
end_time = pygame.time.get_ticks() # Set end_time when game is won
screen.fill(WHITE)
# Draw slots
for slot in slots:
draw_slot(slot)
if slot["filled"]:
pygame.draw.circle(screen, YELLOW, slot["pos"], 5)
# Draw current shape
if not game_won and shapes:
draw_shape(shapes[current_shape_index], shape_pos, shape_angle)
# Draw instructions
instructions = font.render("Arrow keys: Move, R: Rotate, Space: Switch shape", True, BLACK)
screen.blit(instructions, (10, 10))
if game_won:
time_taken = (end_time - start_time) / 1000 # Use end_time instead of current time
# Create a semi-transparent overlay
overlay = pygame.Surface((WIDTH, HEIGHT), pygame.SRCALPHA)
overlay.fill((0, 0, 0, 128)) # Black with 50% opacity
screen.blit(overlay, (0, 0))
win_text = font.render(f"You won!", True, WHITE)
time_text = font.render(f"Time: {time_taken:.2f} seconds", True, WHITE)
screen.blit(win_text, (WIDTH // 2 - win_text.get_width() // 2, HEIGHT // 2 - 50))
screen.blit(time_text, (WIDTH // 2 - time_text.get_width() // 2, HEIGHT // 2 + 50))
# Add a "Play Again" button
play_again_text = font.render("Press SPACE to play again", True, WHITE)
screen.blit(play_again_text, (WIDTH // 2 - play_again_text.get_width() // 2, HEIGHT // 2 + 150))
if keys[pygame.K_SPACE]:
# Reset the game
shapes = [shape.copy() for shape in shape_types]
current_shape_index = 0
for slot in slots:
slot["filled"] = False
shape_pos = Vector2(WIDTH // 2, HEIGHT - 100)
shape_angle = 0
game_won = False
start_time = None
end_time = None
pygame.display.flip()
clock.tick(60)
Also note that, although you can rotate the shape with R, you really never need it with this version. But you can always ask Claude to include a use for it. But at this time I was out of free messages with Claude, so at least for now we end with this version of the game.
I used Python 3.12.4 and pygame 2.6.0.
If you continue from this, please let me know what kind of upgrades you got.