I edit one value of my list but all other values seem to be edited also (full code)

73 views Asked by At

I am completely stumped. I surrounded the crux of the problem with hashtags. Any help is much appreciated!

import pygame
import time
import random

pygame.init()

display_width = 600
display_height = 600
display = pygame.display.set_mode((display_width, display_height))
pygame.display.set_caption('Snake')
clock = pygame.time.Clock()
fps = 10

white = (255, 255, 255)
red = (200, 0, 0)
green = (0, 200, 0)
blue = (0, 0, 200)
black = (0, 0, 0)

def extend_snake(snake):
    x = snake[len(snake) - 1][0]
    y = snake[len(snake) - 1][1]
##    for i in snake:
##        print(i)
    return ([x, y])

def spawn_fruit():
    x = random.randrange(fruit_rad, display_width - fruit_rad, 2 * fruit_rad)
    y = random.randrange(fruit_rad, display_height - fruit_rad, 2 * fruit_rad)       
    return ((x, y))

def pause():
    while True:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                quit()
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_p:
                    return

score = 0

snake = []
snake_size = 10
snake.append([display_width / 2, display_height / 2])
snake_dx = 0
snake_dy = 0

fruit = []
fruit_count = 5
fruit_rad = 5
for a in range(fruit_count):
    fruit.append(spawn_fruit())

while True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            quit()
        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_p:
                pause()         
            elif event.key == pygame.K_a or event.key == pygame.K_LEFT:
                snake_dx = -snake_size
                snake_dy = 0
            elif event.key == pygame.K_d or event.key == pygame.K_RIGHT:
                snake_dx = snake_size
                snake_dy = 0
            elif event.key == pygame.K_w or event.key == pygame.K_UP:
                snake_dy = -snake_size
                snake_dx = 0
            elif event.key == pygame.K_s or event.key == pygame.K_DOWN:
                snake_dy = snake_size
                snake_dx = 0

    print(snake)
    for coord in fruit:
        if snake[0][0] + fruit_rad == coord[0] and snake[0][1] + fruit_rad == coord[1]:
            fruit.remove(coord)
            fruit.append(spawn_fruit())
            snake.append(extend_snake(snake))
            score += 1
            fps += 1

    for i in range(len(snake) - 1, 0, -1):
        snake[i] = snake[i - 1]
################################################
    try:
        print('1', snake[1])
    except:
        pass
    snake[0][0] += snake_dx
    snake[0][1] += snake_dy
    try:
        print('2', snake[1])
    except:
        pass
#########################################################
    display.fill(white)
    for coord in fruit:
        pygame.draw.circle(display, red, coord, fruit_rad)
    for coord in snake:
        pygame.draw.rect(display, black, [coord[0], coord[1], snake_size, snake_size])

    pygame.display.update()
    clock.tick(fps)

This will return for example:
1 (100, 100)
2 (110, 100)

No matter where I print(snake), every list is the same within it. Could somebody please explain why this is happening and what I can do to prevent it?

2

There are 2 answers

0
Mike On

Setting snake[i] = snake[i-1] makes them the same object and thus explaining why they were both being edited even though the code only edited one of them.

0
Anand S Kumar On

When you are doing - snake[i] = snake[i - 1] , you are just passing the reference of the snake[i - 1] to snake[i] . And this seems to happen for all i

Then when you make any changes inside anywhere inside snake[i] you are actually making the changes to the referenced object, hence the changes reflect in all other snake[i] as well.

For your logic to work, you need to use copy.deepcopy to create deep copies of the objects, so that the changes are not reflected in other snake[i]s

In your case you would need to do -

import copy
for i in range(len(snake) - 1, 0, -1):
    snake[i] = copy.deepcopy(snake[i - 1])

Examples -

>>> l = [1,2,3]
>>> l1 = l
>>> l
[1, 2, 3]
>>> l1
[1, 2, 3]
>>> l1.pop(1)
2
>>> l1
[1, 3]
>>> l
[1, 3]
>>> import copy
>>> l2 = copy.deepcopy(l)
>>> l2
[1, 3]
>>> l2.append(4)
>>> l2
[1, 3, 4]
>>> l
[1, 3]
>>> l1
[1, 3]