add a reasoning effort option

#31
by TheBigBlockPC - opened

the model while reasoning is quite inefficent when reasongin often resulting in a bunch of unnesesarry text, asking it to generate the game snake results in it thinking for minutes on end to a point where the vrtam gets limiting.
a option to set it to low would be very useful for getting quicker responses while a high reasoning effort would be useful for very complex tasks.

Here is a example of a reasoning output when asked to program the game snake using pysthon and pygame with the curtrent model:

Okay, the user wants me to create a simple Snake game using Python and Pygame. Let me think about how to approach this step by step.

First, I need to recall the basics of Pygame. I remember that Pygame is a set of Python modules designed for writing video games. So, I'll need to import the Pygame library. Let me start by importing pygame and checking the version in case there are any compatibility issues.

Next, setting up the game window. The user probably wants a window that's not too big but manageable. Maybe 600x600 pixels divided into a grid. Let's see, if each snake segment and the food are squares of 20x20, then the grid can be 30x30 (since 30*20=600). That makes calculations easier.

I'll need to initialize Pygame and set up the display. The caption can be "Snake Game" to make it clear. The game clock is important for controlling the frame rate and updating the screen smoothly. Maybe 10 FPS to start with, but that might be too slow. Wait, the snake's speed is also a factor. Let's see, maybe 10 FPS is okay for the initial version, but perhaps I should make that adjustable.

The snake's initial position should be in the center of the screen. Let's say (10, 10) in grid coordinates, which translates to (200, 200) pixels. The direction can start as right. The snake's body can be a list where each element is a tuple representing the coordinates. Initially, just one block.

Then there's the food. The food should spawn randomly on the grid. I'll need a function to generate a random position that's not occupied by the snake. The color can be red, and it's a square at that position.

The game loop will handle events like quitting, checking for key presses to change direction. The snake moves by adding a new head in the current direction and removing the tail, unless it eats the food, in which case the tail stays, making the snake longer.

Collision detection is crucial. If the snake hits the wall (edge of the screen) or itself, the game should end. So, after moving the snake, check if the head is outside the boundaries or overlaps with any body part.

Scoring: Each time the snake eats food, the score increases. Displaying the score on the screen can be done using Pygame's font module. Wait, do I need to initialize the font? I think so. So I'll need to set up a font and render the text each frame.

Putting it all together, the main steps are:

  1. Initialize Pygame and set up the display and clock.
  2. Define colors, grid size, and initial snake position and direction.
  3. Create functions to handle the snake's movement and food spawning.
  4. The main game loop that handles events, updates the game state, checks for collisions, and redraws everything.
  5. End the game when a collision occurs, maybe with a message.

Wait, I should also think about the direction handling. The snake can only move in four directions, and we need to prevent it from moving in the opposite direction immediately. Like, if moving right, you can't go left immediately. So, the direction changes should be checked to not be the opposite.

Hmm, maybe store the current direction and the next direction. When a key is pressed, check if it's a valid direction change. For example, if moving right, pressing left is invalid, so ignore it. So, in the event loop, when a key is pressed, update the direction variable only if it's a valid direction.

Let me outline the code structure.

First, import and initialize everything:

import pygame
import sys
import random

pygame.init()
screen = pygame.display.set_mode((600, 600))
pygame.display.set_caption("Snake Game")
clock = pygame.time.Clock()

Then define colors:

WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

Grid and snake variables:

snake_pos = [100, 50] # initial position in pixels? Or grid coordinates? Maybe grid coordinates first. Let's think in grid steps. So each block is 20px. So grid coordinates can be integers, and multiply by 20 to get pixel positions.

Wait, better to use grid coordinates. Let's say each grid cell is 20x20. So the snake's position is in terms of grid cells. So initial position could be (10, 10) in grid terms, which would be (200, 200) pixels. So the snake_block size is 20.

snake_block = 20
snake_speed = 15 # or maybe 10? Not sure yet.

Wait, maybe better to have the snake move one grid cell per step. So the speed is how often the snake moves, controlled by the clock.tick(snake_speed). Hmm, perhaps snake_speed is the frames per second, but the movement is done every frame. Let's see.

Wait, in the game loop, each iteration is a frame. So if the clock is set to 10 FPS, the snake moves every 1/10th of a second. So the direction is updated each frame based on the key presses.

The snake's body can be a list of [x, y] positions. The initial body could be something like [[10,10], [9,10], [8,10]] but maybe just start with a single block. Wait, maybe the body starts as a single segment, and grows when eating.

Wait, perhaps the initial body is a list with one element: [[10,10]], and direction is 'RIGHT', so each frame, the snake moves in that direction by adding a new head and removing the tail, unless eating.

Wait, the movement is:

new_head = [snake[0][0] + direction_x, snake[0][1] + direction_y]

Wait, perhaps better to track the direction as a vector. Like direction is (x, y) which can be (1,0), (0,1), etc. So each step, the head moves by direction.

Wait, maybe directions can be stored as a tuple, like direction = [1, 0] (right), then each step, the snake's head is updated by adding direction. So:

snake_pos[0] += direction[0]
snake_pos[1] += direction[1]

Wait, perhaps the snake is represented as a list of blocks, each block is (x, y) in grid coordinates. So the body is a list of positions, and each step, the new head is added to the front, and the last element is removed unless the snake eats.

Wait, perhaps the code structure is:

snake_block = 20
snake_step = snake_block # movement in grid steps?

snake_pos = [ [10, 10], [9,10], [8,10] ] # initial body with 3 blocks? Or start with one?

Wait, maybe start with one block. Let's see.

Wait, maybe the snake's body is a list, and each time it moves, the new head is added, and the tail is removed unless the snake has eaten. So:

snake_body = [[10,10]] # initial position in grid coordinates (each unit is 20px)
food_pos = generate_food() # random position not in snake_body

Then, each frame:

  • Check for events (key presses to change direction)
  • Update snake direction (but prevent immediate reverses)
  • Move the snake: new_head = current_head + direction
  • Check if new_head is on food: if yes, eat it (don't remove the tail, generate new food)
  • Check for collisions (wall or self)
  • Update the snake's body by adding new_head to front and removing last element (unless food was eaten)
  • Draw everything

So for direction handling:

current_dir = 'RIGHT' # or as vectors
possible directions: up, down, left, right. Each direction is a (dx, dy) tuple. Like right is (1, 0), left (-1, 0), up (0, -1), down (0,1). Wait, but in grid coordinates, maybe it's better to have direction as (x, y) increments. So direction can be stored as a list like [1,0], and each step, the head moves by that.

Wait, maybe better to represent direction as a tuple (dx, dy). For example, moving right would be (1, 0), so each step the x increases by 1 (grid unit), so the actual pixel position is (x * snake_block, y * snake_block). So when moving right, the next position is (current_x + 1, current_y).

So the snake's direction is stored as (dx, dy). The initial direction is (1, 0).

Now, when handling key events:

if event.key == pygame.K_UP:
if current direction isn't down (since can't go back immediately)
then set direction to (0, -1)
Similarly for other keys.

So need to prevent opposite directions immediately. For example, if moving right, pressing left is invalid, so direction remains right.

So, in code:

direction = [1, 0] # right initially

Then, when a key is pressed, check the current direction and only allow perpendicular directions or the same.

Wait, the direction can be changed to any direction except the opposite. For example, if moving right, can go up or down, but not left.

So, for each key:

For example, when pressing left arrow:

new_dir = [-1, 0]
if current direction is not (1,0), then set direction to new_dir.

Wait, perhaps better to have a variable for the direction, and when handling keys, only allow changes that are not opposite.

Alternatively, store the direction as a variable, and when a key is pressed, check if the new direction is valid (not opposite).

Alternatively, just let the user change direction freely except that you can't reverse direction immediately. Wait, perhaps it's better to allow any direction except the opposite. For example, if moving right, pressing left would make it go left, which is immediate reverse. Maybe that's allowed? Or perhaps it's better to prevent that.

Hmm, maybe it's better to allow direction changes except the opposite. So, for example, if current direction is right (dx=1), then pressing left (dx=-1) would be invalid, so ignore it. So:

current_dir = (dx, dy)

When handling a key press for direction change:

new_dir = (dx, dy)
if (current_dir[0] + new_dir[0], current_dir[1] + new_dir[1]) != (0,0):
then it's allowed. Wait, perhaps better to check that the new direction is not opposite.

Alternatively, for each key:

if the new direction is not the opposite of current direction, then set it.

Like:

if the current direction is right (1,0), then pressing left (-1,0) is opposite, so ignore.

So in code:

if event.key == pygame.K_LEFT:
if direction != [1, 0]:
direction = [-1, 0]
Similarly for others.

Wait, but direction is a list, so maybe better to use tuples for direction. Let me think:

direction = [1, 0] # right

When pressing left:

new_dir = [-1, 0]

if direction[0] != -new_dir[0] and direction[1] != -new_dir[1], but perhaps it's easier to check:

if not (direction[0] == -new_dir[0] and direction[1] == -new_dir[1]):

Wait, perhaps better to have a helper function or just check for each case.

Alternatively, just allow any direction except the opposite. So for each key, when pressed, set the direction to the corresponding direction, but only if it's not the opposite of current direction.

So for example, if current direction is right (1,0):

  • pressing left (new_dir (-1,0)) is opposite, so ignore.

  • pressing up or down is allowed.

So code:

if event.key == pygame.K_LEFT and direction != [1, 0]:
direction = [-1, 0]

Similarly for other keys.

That's manageable.

Now, the movement:

Each frame, the snake's head moves by direction. So:

new_head = [snake_body[0][0] + direction[0], snake_body[0][1] + direction[1]]

Then check for collision with walls:

if new_head[0] < 0 or new_head[0] >= grid_width (30?), or same for y.

Wait, grid is 30x30 (since 600/20=30). So the maximum x and y can be 29 (since 0-based). So if new_head[0] is >=30 or <0, then game over.

Also check if the new head is in the snake's body (except the first element, but actually, the body includes all parts, so if the new head is in the body, then collision with self).

Wait, the snake's body is a list where the first element is the head. So when moving, the new head is added to the front, and the tail is removed unless food was eaten.

So collision with self is when new_head is in snake_body[1:], because the head is at 0, and the rest are body parts.

So, after computing new_head, check:

if new_head in snake_body[1:] --> collision.

Now, the food spawning:

food_pos needs to be a position not occupied by the snake. So when generating, pick a random (x,y) in grid, and check if it's not in snake_body. Repeat until found.

So a function like:

def generate_food(snake_body):
while True:
x = random.randint(0, grid_size-1)
y = random.randint(0, grid_size-1)
if (x,y) not in snake_body:
return (x,y)

Wait, grid_size is 30? Since 600 / 20 = 30. So grid_size = 30.

Wait, the grid is 30x30 cells (0-29 in each direction). So yes.

So when generating food, pick x and y between 0 and 29 inclusive.

Now, putting it all together in code:

Initialize variables:

snake_block = 20
snake_speed = 15 # frames per second

grid_size = 30 # 30x30 grid (each cell 20px)

snake_pos = [[10, 10]] # starting position in grid coordinates (10,10 is 200,200 pixels)
direction = [1, 0] # moving right initially

food_pos = generate_food(snake_pos)
food_spawned = True # maybe not needed, just generate once initially.

score = 0

Then, in the game loop:

while running:

for event in pygame.event.get():
    if event.type == pygame.QUIT:
        running = False
    elif event.type == pygame.KEYDOWN:
        if event.key == pygame.K_UP and direction != [0, 1]:
            direction = [0, -1]
        elif event.key == pygame.K_DOWN and direction != [0, -1]:
            direction = [0, 1]
        elif event.key == pygame.K_LEFT and direction != [1, 0]:
            direction = [-1, 0]
        elif event.key == pygame.K_RIGHT and direction != [-1, 0]:
            direction = [1, 0]

# move the snake
new_head = [snake_pos[0][0] + direction[0], snake_pos[0][1] + direction[1]]

# check collision with walls
if new_head[0] < 0 or new_head[0] >= grid_size or new_head[1] <0 or new_head[1] >= grid_size:
    game_over = True

# check collision with self
if new_head in snake_pos[1:]:
    game_over = True

# check if ate food
if new_head == food_pos:
    score +=1
    food_spawned = False  # need to generate new food
else:
    # remove the tail
    snake_pos.pop()

# add new head
snake_pos.insert(0, new_head)

# spawn food if needed
if not food_spawned:
    food_pos = generate_food(snake_pos)
    food_spawned = True

# draw everything
screen.fill(BLACK)
for pos in snake_pos:
    pygame.draw.rect(screen, GREEN, pygame.Rect(pos[0]*snake_block, pos[1]*snake_block, snake_block, snake_block))
pygame.draw.rect(screen, RED, pygame.Rect(food_pos[0]*snake_block, food_pos[1]*snake_block, snake_block, snake_block))
# draw score
# etc.

Wait, but in the code above, the direction checks for the key presses are important. For example, when pressing up, direction can't be down (the opposite). So in the code for K_UP: direction can't be down (which is [0,1]? Wait, direction is stored as [dx, dy]. So moving down would be direction [0,1], because each step increases y by 1. So when moving down, pressing up would be direction [0, -1], which is opposite in dy. So the check for K_UP should ensure that the current direction's dy is not the negative of the new direction's dy. So in code:

if event.key == pygame.K_UP and direction[1] != 1: # current direction's dy is not 1 (down)
direction = [0, -1]

Wait, direction for down is [0,1], so the new direction's dy is -1. So the check is that the current direction's dy isn't 1 (so that you can't go up when moving down). So that's correct.

Hmm, this logic needs to be correct for all keys.

Now, drawing the snake and food: each position in snake_pos is multiplied by snake_block (20) to get the pixel position. The rectangle is drawn at that position with size 20x20.

The score can be displayed using Pygame's font. Need to initialize the font, create a font object, then render the text each frame.

Adding the game over condition: when game_over is True, show a message and wait for a key to exit or restart.

Wait, in the code above, when game_over is set to True, the loop should break, and then display game over. So maybe after the collision checks, if game_over is True, then exit the loop.

Putting all together, here's a rough structure of the code.

Wait, also, the clock.tick(snake_speed) should be in the loop to control the speed.

Potential issues:

  • The snake might move too fast. Maybe adjust snake_speed (the FPS). Let's see, if snake_speed is 10, then the snake moves every 1/10 sec. With 10 FPS, that's manageable.

  • The food generation: need to ensure that the food is not placed on the snake.

  • The direction changes: making sure that the user can't reverse immediately.

Testing this code in my mind, I might have missed some details. Let me try to code it step by step.

Wait, perhaps better to write the code step by step and then test.

Wait, in the movement part, when the snake eats the food, we don't remove the tail, so the snake grows. The code above has:

if new_head == food_pos:
score +=1
food_spawned = False
else:
snake_pos.pop()

Yes, that's correct. Because when eating, we don't pop the tail, so the snake length increases by 1.

Now, the generate_food function:

def generate_food(snake_body):
while True:
x = random.randint(0, grid_size -1)
y = random.randint(0, grid_size -1)
if (x, y) not in snake_body:
return (x, y)

Wait, snake_body is a list of lists, like [[10,10], [9,10], ...], so checking if (x,y) is in the list of positions. Since each element is a list, perhaps better to convert each position to a tuple for comparison. Alternatively, check for each pos in snake_body:

if [x,y] not in snake_body:

But lists are unhashable, so tuples would be better. Hmm, perhaps better to store the snake's positions as tuples, so they can be checked in sets. But maybe for simplicity, just use lists and check with 'in'.

Alternatively, in generate_food, the snake_body is a list of lists, so the check is:

if [x,y] not in snake_body:

But in the code above, the new_head is compared to food_pos which is (x,y) as a tuple? Wait, no, in the code above, food_pos is stored as a list [x,y] or a tuple?

Wait in the generate_food function, returns (x,y) as a tuple, but in the snake_pos, each element is a list. So comparing [new_head] (a list) with (x,y) (a tuple) would not match. Wait that's a problem.

Ah, right! So need to make sure that the types match. Let's see:

If snake_pos contains lists like [10,10], and food_pos is a tuple (10,5), then comparing new_head (which is a list [10,5]?) to food_pos (tuple (10,5)) would be False.

So better to use the same type for all positions. Let's use lists for everything.

Modify generate_food to return a list:

return [x,y]

Then in the code, food_pos is a list.

Alternatively, use tuples for all positions. Let's see.

Alternatively, convert new_head to a tuple when comparing. Hmm, perhaps better to stick with lists.

So in generate_food:

return [x,y]

Then, in the code, food_pos is a list, and new_head is a list, so the comparison is okay.

Another potential issue is that when the snake moves, the new_head could be exactly where the food is, so the snake eats it. Then, we don't pop the tail, so the snake grows by one.

Now, the drawing part:

For each position in snake_pos, draw a rectangle at (pos[0]*20, pos[1]*20), size 20x20.

The food is similarly drawn at food_pos's coordinates.

The score can be displayed using:

font = pygame.font.Font(None, 36)
text = font.render("Score: " + str(score), True, (255,255,255))
screen.blit(text, (10, 10))

Need to initialize the font first.

Putting all together, here's the code outline:

Initialize Pygame, set up screen and clock.

Define colors.

Set grid_size = 30, snake_block=20.

Initialize snake_pos as [[10,10]], direction as [1,0].

Generate initial food.

Initialize score=0.

Set running = True, game_over = False.

Main loop:

while running:

for event in pygame.event.get():

    handle quit and key presses.

if game_over:

    break or handle game over screen.

else:

    move snake, check collisions.

draw everything.

update display.

clock.tick(snake_speed)

Wait, but in the code above, the movement and collision checks are done inside the loop, so perhaps better structure:

Inside the main loop:

Handle events first.

Then, if not game_over, proceed to move the snake.

So:

running = True

game_over = False

while running:

for event in pygame.event.get():

    if event.type == pygame.QUIT:

        running = False

    elif event.type == pygame.KEYDOWN and not game_over:

        # handle direction changes

if game_over:

    # display game over message and wait for key to exit

else:

    # move the snake, check for collisions, etc.

Wait, maybe the game_over flag is set when collision occurs, then we stop moving and just show the message.

So in the code:

after computing new_head:

if collision with wall or self:

game_over = True

then, if game_over is True, we don't move anymore, just draw the game over screen.

Hmm, perhaps better to handle the game_over outside the main loop.

Alternatively, once game_over is set, the loop continues but doesn't process movement, and shows a message.

Alternatively, break out of the loop and show game over.

Wait, perhaps after setting game_over to True, the loop continues, but the movement code is skipped, and the screen is redrawn with the game over message.

So, putting all together, here's the code step by step.

Now, let's code this step by step, making sure all parts are covered.

Wait, I need to also handle the drawing of the game over message.

Hmm, perhaps after the game_over is set, in the drawing part, display a message.

Also, the initial code may have some syntax errors. For example, the generate_food function needs to be defined before it's used.

Putting all together, here's the code:

import pygame
import sys
import random

pygame.init()

Constants

WIDTH, HEIGHT = 600, 600
GRID_SIZE = 30
SNAKE_BLOCK = WIDTH // GRID_SIZE # 20px
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Snake Game")
clock = pygame.time.Clock()

def generate_food(snake_body):
while True:
x = random.randint(0, GRID_SIZE - 1)
y = random.randint(0, GRID_SIZE - 1)
if [x, y] not in snake_body:
return [x, y]

def main():
snake_pos = [[GRID_SIZE//2, GRID_SIZE//2]] # start at center
direction = [1, 0] # right
food_pos = generate_food(snake_pos)
score = 0
game_over = False

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        elif event.type == pygame.KEYDOWN and not game_over:
            if event.key == pygame.K_UP and direction != [0, 1]:
                direction = [0, -1]
            elif event.key == pygame.K_DOWN and direction != [0, -1]:
                direction = [0, 1]
            elif event.key == pygame.K_LEFT and direction != [1, 0]:
                direction = [-1, 0]
            elif event.key == pygame.K_RIGHT and direction != [-1, 0]:
                direction = [1, 0]

    if not game_over:
        # Move the snake
        new_head = [snake_pos[0][0] + direction[0], snake_pos[0][1] + direction[1]]

        # Check collisions
        if (new_head[0] < 0 or new_head[0] >= GRID_SIZE or
            new_head[1] < 0 or new_head[1] >= GRID_SIZE):
            game_over = True
        if new_head in snake_pos[1:]:
            game_over = True

        # Check if ate food
        if new_head == food_pos:
            score += 1
            food_pos = generate_food(snake_pos)
        else:
            snake_pos.pop()

        snake_pos.insert(0, new_head)

    # Drawing
    screen.fill(WHITE)
    if not game_over:
        for pos in snake_pos:
            pygame.draw.rect(screen, GREEN, (pos[0]*SNAKE_BLOCK, pos[1]*SNAKE_BLOCK, SNAKE_BLOCK, SNAKE_BLOCK))
        pygame.draw.rect(screen, RED, (food_pos[0]*SNAKE_BLOCK, food_pos[1]*SNAKE_BLOCK, SNAKE_BLOCK, SNAKE_BLOCK))
    else:
        font = pygame.font.Font(None, 36)
        text = font.render("Game Over! Score: " + str(score), True, (255,0,0))
        text_rect = text.get_rect(center=(WIDTH//2, HEIGHT//2))
        screen.blit(text, text_rect)

    # Update display
    pygame.display.flip()
    clock.tick(10)  # Adjust speed here

if name == "main":
main()

Wait, but in this code, the initial direction is [1,0], so moving right. The snake starts at the center (15,15?), which is 15*20=300, so center of the screen. That's better than [10,10].

Wait, in the code above, snake_pos starts at [GRID_SIZE//2, GRID_SIZE//2], which for 30 grid is 15, so yes.

But when moving, the snake's direction is [1,0], so moving right. The first move would take it to (16, 15), but if that's within the grid (since GRID_SIZE is 30, indexes go up to 29?), then okay.

Wait, the grid is 30x30, so coordinates from 0 to 29. So 15 is okay.

Potential issues:

  • The game_over message is displayed but the loop continues. The user can press a key to exit? Currently, after game_over, the loop continues, but the game is over. So perhaps after game_over, we should wait for a key press to exit.

Alternatively, after setting game_over, the loop continues, but the snake doesn't move anymore. The user can close the window.

Hmm, in the code above, when game_over is True, the snake's movement code is skipped, so the snake stays in place. The game over message is displayed each frame.

The user can close the window to exit, or perhaps press a key to restart? But the current code doesn't handle that. Maybe add a restart option, but for simplicity, just allow closing the window.

Another thing: the initial snake is a single block. So when it eats food, it becomes two blocks, etc.

Testing the code, I think it should work, but let me check some parts.

In the generate_food function, since the snake starts at [[15,15]], the first food is generated somewhere else.

In the movement code, after checking collision, if game_over is set, then the snake stops moving.

The clock.tick(10) sets the FPS to 10, so the snake moves every 1/10 seconds.

The drawing is done every frame.

Potential issue: when the snake moves off the screen, the collision is detected correctly.

Yes, because new_head's coordinates are checked against 0 and GRID_SIZE-1 (since indexes go up to 29). Wait, no, in the code, the check is:

if new_head[0] <0 or new_head[0] >= GRID_SIZE:

GRID_SIZE is 30, so new_head[0] can be up to 29, so when it's 30, it's over. So yes, correct.

Another thing: the food is generated with generate_food(snake_pos), which checks if the position is not in the snake's body. So the food won't be on the snake.

The score is displayed correctly when game over.

I think this should work. Let me see if there's any syntax error.

Wait in the main function, after the first while True: loop, the events are handled, then movement if not game_over, then drawing.

Yes, but the loop is infinite. To exit, you have to close the window, which is handled by the QUIT event.

Yes, this should work.

Another thing: the snake's initial direction is right, but when the snake is at (15,15), moving right would take it to 16,15, which is okay.

Testing edge cases:

  • Moving into wall: game over.

  • Eating food: snake grows.

  • Hitting self: game over.

Yes.

So this should be a functional simple snake game.

Here's a simple Snake game implemented using Python and Pygame:

import pygame
import sys
import random

# Initialize Pygame
pygame.init()

# Game constants
WIDTH, HEIGHT = 600, 600
GRID_SIZE = 30
SNAKE_BLOCK = WIDTH // GRID_SIZE  # Each snake block is 20x20 pixels

WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Snake Game")
clock = pygame.time.Clock()

def generate_food(snake_body):
    """Generate new food position not overlapping with the snake"""
    while True:
        x = random.randint(0, GRID_SIZE - 1)
        y = random.randint(0, GRID_SIZE - 1)
        if [x, y] not in snake_body:
            return [x, y]

def main():
    # Initial snake position (center of the grid)
    snake_pos = [[GRID_SIZE//2, GRID_SIZE//2]]  
    direction = [1, 0]  # Start moving right
    food_pos = generate_food(snake_pos)
    score = 0
    game_over = False

    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN and not game_over:
                # Change direction based on arrow keys
                if event.key == pygame.K_UP and direction != [0, 1]:
                    direction = [0, -1]
                elif event.key == pygame.K_DOWN and direction != [0, -1]:
                    direction = [0, 1]
                elif event.key == pygame.K_LEFT and direction != [1, 0]:
                    direction = [-1, 0]
                elif event.key == pygame.K_RIGHT and direction != [-1, 0]:
                    direction = [1, 0]

        if not game_over:
            # Move the snake
            new_head = [snake_pos[0][0] + direction[0], snake_pos[0][1] + direction[1]]

            # Check collisions
            if (new_head[0] < 0 or new_head[0] >= GRID_SIZE or 
                new_head[1] < 0 or new_head[1] >= GRID_SIZE):
                game_over = True
            if new_head in snake_pos[1:]:  # Check collision with self
                game_over = True

            # Check if food was eaten
            if new_head == food_pos:
                score += 1
                food_pos = generate_food(snake_pos)
            else:
                snake_pos.pop()  # Remove tail if no food eaten

            snake_pos.insert(0, new_head)  # Add new head

        # Draw everything
        screen.fill(WHITE)
        if not game_over:
            # Draw snake
            for pos in snake_pos:
                pygame.draw.rect(screen, GREEN, 
                                (pos[0]*SNAKE_BLOCK, pos[1]*SNAKE_BLOCK, 
                                 SNAKE_BLOCK, SNAKE_BLOCK))
            # Draw food
            pygame.draw.rect(screen, RED, 
                            (food_pos[0]*SNAKE_BLOCK, food_pos[1]*SNAKE_BLOCK, 
                             SNAKE_BLOCK, SNAKE_BLOCK))
        else:
            # Game over screen
            font = pygame.font.Font(None, 36)
            text = font.render(f"Game Over! Score: {score}", True, RED)
            text_rect = text.get_rect(center=(WIDTH//2, HEIGHT//2))
            screen.blit(text, text_rect)

        # Update display
        pygame.display.flip()
        clock.tick(10)  # Control game speed (10 FPS)

if __name__ == "__main__":
    main()

How to Play:

  1. Run the script using Python 3 with Pygame installed.
  2. Use arrow keys to control the snake's direction.
  3. Eat the red food to grow longer and increase your score.
  4. Avoid hitting the walls or your own body to stay alive.

Key Features:

  • Grid-based movement (30x30 grid)
  • Collision detection for walls and self-collision
  • Scoring system that increases with each food eaten
  • Responsive controls with arrow keys
  • Clean visual design with simple colors

To Install Pygame:

If you don't have Pygame installed, use:

pip install pygame

This is a basic implementation. You can enhance it by adding:

  • Sound effects
  • Different difficulty levels
  • High score tracking
  • Customizable colors
  • Pause functionality
  • Leaderboard
  • More levels or obstacles

We NEED this now.

Sign up or log in to comment