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()
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: