Search code examples
pythonpygameindex-error

How is print(count) resulting in a list index out of range error?


I am just fooling around and decided to make a visualization of Gaussian distribution, and somehow this error happens to exist. I have never seen this error before, and the weirdest part is that somehow it doesn't happen every time the loop runs. It's completely random. Sometimes it errors on the first iteration of the loop, and sometimes it doesn't error at all. How on earth can the print() function return an index error when passed an int. Here is all of the code:

import math
import pygame
import os

wS = 500

n = 50

os.environ["SDL_VIDEO_WINDOW_POS"] = "%d, %d" % (5, 5)

pygame.init()

window = pygame.display.set_mode((wS, wS), 0, 0, 0)
li = [math.floor(random.gauss(350, 20)) for i in range(50)]
lmax = 0
lmin = 1000
off = wS/2

leng = len(li)

for i in range(len(li)):
    if li[i] > lmax:
        lmax = li[i]

xV = wS/n
xV2 = wS/lmax
print(li)

def run():
    global li
    global xV
    global lmax
    global off


    keys = pygame.key.get_pressed()
    count = 0
    p = pygame.PixelArray(window)
    while not keys[pygame.K_ESCAPE] and not keys[pygame.K_SPACE] and count < (leng - 1):
        print(count)
        event = pygame.event.get()
        keys = pygame.key.get_pressed()

        x = int(xV * count)

        y = int(off + ((li[count]/lmax) * off))

        p[x][y] = (255, 255, 255)
        count+=1
    print("done")
    pygame.display.update()
    keys = pygame.key.get_pressed()
    while not keys[pygame.K_ESCAPE] and not keys[pygame.K_SPACE]:
        event = pygame.event.get()
        keys = pygame.key.get_pressed()

run()

The error:

Traceback (most recent call last):
  File "*redacted*", line 58, in <module>
    run()
  File "*redacted*", line 41, in run
    print(count)
IndexError: array index out of range

Solution

  • When you use the pygame.PixelArray, os events are blocked. pygame.event.get() and pygame.key.get_pressed() will both return errors while the pixel array surface is locked.

    Here is the updated code. I removed the events from the loop. I also added a check for the x,y coordinates to be sure they are within the array.

    import math
    import pygame
    import os
    import random
    
    wS = 500
    
    n = 50
    
    os.environ["SDL_VIDEO_WINDOW_POS"] = "%d, %d" % (5, 5)
    
    pygame.init()
    
    window = pygame.display.set_mode((wS, wS), 0, 0, 0)
    
    li = [math.floor(random.gauss(350, 20)) for i in range(50)]
    lmax = 0
    lmin = 1000
    off = wS/2
    
    leng = len(li)
    
    for i in range(len(li)):
        if li[i] > lmax:
            lmax = li[i]
    
    xV = wS/n
    xV2 = wS/lmax
    print(li)
    
    def run():
        global li, xV, lmax, off
    
        count = 0
        p = pygame.PixelArray(window)  # lock surface for drawing
    
        while count < (leng - 1):
            x = int(xV * count)
            y = int(off + ((li[count]/lmax) * off))
            if x < wS and y < wS: p[x,y] = (255, 255, 255)
            count+=1
            
        p.close()  # unlock surface
            
        print("done")
        pygame.display.update()
        keys = pygame.key.get_pressed()
        while not keys[pygame.K_ESCAPE] and not keys[pygame.K_SPACE]:
            event = pygame.event.get()
            keys = pygame.key.get_pressed()
    
    run()