-1

I'm trying to make a grid towards the middle of the window and can get the tiles to update however if I click where the tiles are visibly on screen I get an error.

The input seems to be stuck at the top left. How can I update this? Thanks!

line 49, IndexError: list index out of range

import pygame

pygame.init()
pygame.font.init()

colorBlack = (000, 000, 000); colorWhite = (255, 255, 255); colorRed = (255, 000, 000)

winWidth = 1280; winHeight = 720; FPS = 30
winDisplay = pygame.display.set_mode((winWidth, winHeight))
FPSClock = pygame.time.Clock()
running = True

def drawGrid():
    blockSize = 47 #Pixel count for each grid block
    gridSize = 10 #Size of grid (5x5, 10x10, etc.)
    gridFrame = 479 #Size of the grid frame (in pixels)
    gridFrameX = 501 #X position of the grid frame
    gridFrameY = 221 #Y position of the grid frame
    gridFrameRect = (gridFrameX, gridFrameY, gridFrame, gridFrame) #Grid frame rectangle
    gridSolution = [[0] * gridSize for _ in range(gridSize)] #Grid solution (2D array)
    gridPuzzle = [[0] * gridSize for _ in range(gridSize)] #Grid puzzle (2D array)

    gridPuzzle[0][0] = 1 #Set the first cell of the puzzle to 1 (black)

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    quit()
                if event.key == pygame.K_r:
                    drawGrid()
            
            if event.type == pygame.MOUSEBUTTONDOWN:
                x, y = pygame.mouse.get_pos()
                print("Mouse position: ", x, y)
                gridRow = y // blockSize
                gridCol = x // blockSize
                gridPuzzle[gridRow][gridCol] = 1 - gridPuzzle[gridRow][gridCol]
                print("Grid cell toggled at: ", gridRow, gridCol)
        
        pygame.draw.rect(winDisplay, colorBlack, (0, 0, 501, winHeight))
        pygame.draw.rect(winDisplay, colorBlack, (501, 0, 772, 221))

        for gameRow in range(gridSize):
            for gameCol in range(gridSize):
                rect = (gridFrameX + gameCol * blockSize, gridFrameY + gameRow * blockSize, blockSize, blockSize)
                pygame.draw.rect(winDisplay, colorBlack, rect, 1) #Draw the grid cell outline
                if gridPuzzle[gameRow][gameCol] == 1:
                    pygame.draw.rect(winDisplay, colorRed, rect) #Draw the filled cell
                if gridPuzzle[gameRow][gameCol] == 0:
                    pygame.draw.rect(winDisplay, colorWhite, rect) #Draw the empty cell
        
        pygame.draw.rect(winDisplay, colorBlack, gridFrameRect, 1) #Draw the grid
        pygame.display.update()
        FPSClock.tick(FPS)

def quit():
    running = False
    pygame.quit()

if __name__ == "__main__":
    drawGrid()
3
  • always put full error message because there are other useful information. Commented Apr 14 at 6:39
  • Maybe first use print() (and print(type(...)), print(len(...)), etc.) to see which part of code is executed and what you really have in variables. It is called "print debugging" and it helps to see what code is really doing. Commented Apr 14 at 6:40
  • IndexError can means you calculate wrong value(s) gridRow, gridCol and now gridPuzzle[gridRow][gridCol] try to get element which doesn't exist. You could use print() to check values gridRow = y // blockSize gridCol = x // blockSize Commented Apr 14 at 6:47

1 Answer 1

1

The error you're encountering (IndexError: list index out of range) is caused by this part of the code:

gridRow = y // blockSize
gridCol = x // blockSize
gridPuzzle[gridRow][gridCol] = 1 - gridPuzzle[gridRow][gridCol]

When you click inside the grid, it is not converting screen coordinates to grid-local coordinates properly.

Another issue is quit() function is defined near the bottom, just before the if __name__ == "__main__": block. Here's the relevant part of your code:

def quit():
    running = False  # This is a local variable and doesn't affect the main loop
    pygame.quit()

quit() is also a built-in Python function. Rename something like def quitGame():

Running is never defined inside drawGrid(). Therefore, make it global.

The full code with correction and improvement is provided below:

import pygame

pygame.init()
pygame.font.init()

colorBlack = (0, 0, 0)
colorWhite = (255, 255, 255)
colorRed = (255, 0, 0)

winWidth = 1280
winHeight = 720
FPS = 30

winDisplay = pygame.display.set_mode((winWidth, winHeight))
pygame.display.set_caption("Centered Grid Toggle Game")
FPSClock = pygame.time.Clock()
running = True

def drawGrid():
    global running

    blockSize = 47
    gridSize = 10
    gridFrame = blockSize * gridSize
    gridFrameX = (winWidth - gridFrame) // 2
    gridFrameY = (winHeight - gridFrame) // 2
    gridFrameRect = (gridFrameX, gridFrameY, gridFrame, gridFrame)
    gridPuzzle = [[0] * gridSize for _ in range(gridSize)]
    gridPuzzle[0][0] = 1

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quitGame()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    quitGame()
                elif event.key == pygame.K_r:
                    drawGrid()
            elif event.type == pygame.MOUSEBUTTONDOWN:
                x, y = pygame.mouse.get_pos()
                if gridFrameX <= x < gridFrameX + gridFrame and gridFrameY <= y < gridFrameY + gridFrame:
                    gridRow = (y - gridFrameY) // blockSize
                    gridCol = (x - gridFrameX) // blockSize
                    if 0 <= gridRow < gridSize and 0 <= gridCol < gridSize:
                        gridPuzzle[gridRow][gridCol] = 1 - gridPuzzle[gridRow][gridCol]

        winDisplay.fill(colorBlack)

        for row in range(gridSize):
            for col in range(gridSize):
                rect = (
                    gridFrameX + col * blockSize,
                    gridFrameY + row * blockSize,
                    blockSize,
                    blockSize
                )
                pygame.draw.rect(winDisplay, colorBlack, rect, 1)
                color = colorRed if gridPuzzle[row][col] == 1 else colorWhite
                pygame.draw.rect(winDisplay, color, rect)

        pygame.draw.rect(winDisplay, colorBlack, gridFrameRect, 2)
        pygame.display.update()
        FPSClock.tick(FPS)

def quitGame():
    global running
    running = False
    pygame.quit()

if __name__ == "__main__":
    drawGrid()

Output:

enter image description here

Sign up to request clarification or add additional context in comments.

2 Comments

first you should describe main problem, and later suggest other modifications :)
I edited the answer with details of issues. Thank you. @furas

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.