ListIndex out of range, not sure why? - python

I've tried inserting the value 1 in a few different ways in the list relevant to the position of the tile in the grid and it keeps on telling me i'm out of range? if I am using len I thought the point was that couldn't happen? what am I overlooking here? this is quite a bit easier to do in pyglet for me but it doesn't translate to pygame since they're both window managers. thank you guys for your time.
import pygame
import time
import random as rnd
from pygame.locals import *
pygame.init()
flags = SCALED | FULLSCREEN | DOUBLEBUF
SCREEN_HEIGHT = 500
SCREEN_WIDTH = 1000
resolution = (SCREEN_WIDTH, SCREEN_HEIGHT)
screen = pygame.display.set_mode(resolution, flags, 16)
# COLOR SCHEME
RED = (255, 0, 0)
BLUE = (100, 100, 255)
BLACK = (0, 0, 0)
clock = pygame.time.Clock()
running = True
cell_width = 5
tick = 0
onelist = []
while running:
tick = tick+1
screen.fill(BLUE)
if tick ==1:
for row in range(0,SCREEN_WIDTH, cell_width):
for col in range(0, SCREEN_HEIGHT, cell_width):
square_coords = ((row*cell_width), (col*cell_width),
(SCREEN_HEIGHT/(cell_width/4)), (SCREEN_WIDTH/(cell_width/4)))
if rnd.random() < .6:
onelist[row].insert(len(onelist[row]), 1)
if rnd.random() >= .6 and rnd.random() < .8:
onelist[row].insert(len(onelist), 2)
else:
onelist[row].insert(len(onelist), 0)

It is very confusing for beginners, especially because it depends on the language, but generally arrays and lists are indexed beginning at zero. This means the first element of any list is [0] and the final element is [len - 1].
What #blorgon is trying to help you to see is that when you check the length of your array, it will be 5 as you expect. But if you just take your list and try to access each element one at a time from 1 - 5, you'll skip the first element and get an error for the last.
So as in the example Blorgon gave,
x = [3, 0, -1, 5]
x[0] = 3
x[1] = 0
x[2] = -1
x[3] = 5
# x[4] Doesn't exist

Related

Display flickering in pygame (how to make my code more efficient) [duplicate]

This question already has an answer here:
Why is the PyGame animation is flickering
(1 answer)
Closed 2 years ago.
Although Python is really slow I want to try to make a 3D game engine in pygame. And I already have a problem: display flickers when I add more than just one object. You can view my code here (to view the result you need to run the test.py file, tdge.py functions as a library). How can I make it more efficient?
Here is the main part of this code:
# this function handles the drawing objects on the display
def draw(game, object):
# updating the background if game.update is True
if game.update:
if game.image_path: game.win.blit(game.image, (0, 0))
else: game.win.fill(game.color)
# checking the type of the given object
if type(object) == Cube:
# getting the height of the game window
height = game.win.get_height()
# getting the width of the game window
width = game.win.get_width()
# getting the X distance between the object and the user
distanceX = game.position[0] - object.position[0]
# getting the Z distance between the object and the user
distanceZ = game.position[2] - object.position[2]
# setting the size of the object that user will actually see
display_size = []
for size in object.size:
if game.position[2] < object.position[2]:
display_size.append(size / distanceZ * 1000)
else: display_size.append(0)
# creating a position list, storing the position of an object on a 3D coordinate plane
position = [width / 2 - distanceX - display_size[0] / 2, height / 2 - object.position[1] - display_size[1] / 2, object.position[2]]
# if player is not "inside" of the object
if game.position[0] > position[0] + object.size[0] / 2 or \
game.position[0] < position[0] - object.size[0] / 2 and \
game.position[1] > position[1] + object.size[1] / 2 or \
game.position[1] < position[1] - object.size[1] / 2 and \
game.position[2] > position[2] + object.size[2] / 2 or \
game.position[2] < position[2] - object.size[2] / 2:
# if the rotation of the player is [0, 0, 0]
if game.rotation == [0, 0, 0]:
# if the rotation of the object is [0, 0, 0]
if object.rotation == [0, 0, 0]:
# drawing a 2D rectangle
pygame.draw.rect(game.win, object.color, ((position[0], position[1]), (display_size[0], display_size[1])))
# if rotation of the object is not [0, 0, 0]
else:
# if the object is rotated on Y axis
if object.rotation[1] != 0:
# getting the sizes on X axis
y_rotation = object.rotation[1]
percent = 100 / (90 / y_rotation)
x_size = display_size[0]
x0 = x_size / 100 * percent
x1 = x_size - x0
number = 255 - (255 / 100 * percent)
# setting the RGB values
color0 = object.color[0] - number if object.color[0] >= number else 0
color1 = object.color[1] - number if object.color[1] >= number else 0
color2 = object.color[2] - number if object.color[2] >= number else 0
# drawing two 2D rectangles based on the data above
pygame.draw.rect(game.win, (color0, color1, color2), ((position[0], position[1]), (x0, display_size[1])))
pygame.draw.rect(game.win, object.color, ((position[0]+x0, position[1]), (x1, display_size[1])))
# else:
# TODO
# write code for displaying object when it is to the right or to the left of the player
# pass
# adding the object if it is not in game.objects
if object not in game.objects:
game.objects.append(object)
else:
error = "You should provide the object of supported type by this library."
raise TypeError(error)
# update the screen so that user will see the difference
pygame.display.update()
The problem is most likely caused by multiple calls to pygame.display.update(). An update of the display at the end of the application loop is sufficient. Multiple calls to pygame.display.update() or pygame.display.flip() cause flickering.
Remove all calls to pygame.display.update() from your code, but call it once at the end of the application loop:
def start_game(game, code=None):
# [...]
while running:
# [...]
pygame.display.update()
clock.tick(120)

Trying to code a grid of squares that disappear when clicked, wrong squares disappear and I have no idea why

I am new to programming and I decided to code the game minesweeper as a way to exercise.
To do this, I started by creating a code that makes a grid of 10 x 10 cells that disappear when clicked. However the squares when clicked sometimes make other squares disappear in an unpredictable way.
Here is a gif showing what happens :
square_disappearing
Clicking the same square could make multiple squares disappear or not and I have no idea what triggers it, which makes me think the problem might not come from my code ? By the way here it is :
import pygame
import sys
listeSuppr = [] # list of squares that shouldn't be drawn
pygame.init()
WIDTH = 800
HEIGHT = 800
GREY = (50, 50, 50)
BLACK = (0, 0, 0)
def add_to_list(a, liste_locale): # looks at the position of the mouse and says what square it corresponds to
a = pygame.mouse.get_pos() # then adds it to the list of squares that shouldn't be drawn (listeSuppr)
print(a)
for x in range(HEIGHT // hauteur):
if hauteur * x < int(list(a)[1]) < hauteur * (x + 1):
break
print(x)
for y in range(WIDTH // longueur):
if longueur*y < int(list(a)[0]) < longueur*(y+1):
break
print(y)
if not [longueur*y, hauteur*x] in listeSuppr:
liste_locale.append([longueur*y, hauteur*x])
print(liste_locale)
longueur = WIDTH//10
hauteur = HEIGHT//10
screen = pygame.display.set_mode((WIDTH, HEIGHT))
game_over = False
while not game_over:
for x in range(HEIGHT//hauteur): # looks if the program should draw the squares or not
for y in range(WIDTH//longueur):
if not [longueur*y, hauteur*x] in listeSuppr:
pygame.draw.rect(screen, GREY, (longueur*y, hauteur*x, int(longueur*0.90), int(hauteur*0.90)))
else:
pygame.draw.rect(screen, BLACK, (longueur * y, hauteur * x, int(longueur * 0.90), int(hauteur * 0.90)))
for event in pygame.event.get():
if event.type == pygame.QUIT: # detects if the game has to close
sys.exit()
elif pygame.mouse.get_pressed() == (1, 0, 0): # detects when right-click has been pressed to delete the square
print(pygame.mouse.get_pos())
add_to_list(0, listeSuppr)
listeSuppr.sort()
print(listeSuppr)
elif pygame.mouse.get_pressed() == (0, 0, 1): # detects when left-click has been pressed to reset the grid
listeSuppr.clear()
pygame.display.update()
Sorry if the code looks like garbage lol. Also sorry for the half french half english names for the vars and fuctions...
If someone knows if there is something wrong with the code or the way I codded the grid, or if it isn't my fault but you know a way to fix the problem, please do tell me !
The issue always happens, when the first loop in add_to_list runs to the end and doesn't find a valid coordinate. This always happens when you click at a pixel, whose x coordinate is dividable by hauteur respectively y coordinate is divisible by longueur. In this case the condition hauteur * x < int(list(a)[1]) < hauteur * (x + 1) and/or longueur*y < int(list(a)[0]) < longueur*(y+1) is never fulfilled.
You have to evaluate <= rather than < for either the 1st or 2nd condition, to cover the full range of pixels:
if hauteur * x < int(list(a)[1]) < hauteur * (x + 1):
if hauteur * x <= int(list(a)[1]) < hauteur * (x + 1):
if longueur*y < int(list(a)[0]) < longueur*(y+1):
if longueur*y <= int(list(a)[0]) < longueur*(y+1):
Anyway, the code can be simplified by using the // (floor division) operator to compute the cell indices:
def add_to_list(a, liste_locale):
a = pygame.mouse.get_pos()
print(a)
x = a[1] // hauteur
print(x)
y = a[0] // longueur
print(y)
if not [longueur*y, hauteur*x] in listeSuppr:
liste_locale.append([longueur*y, hauteur*x])
print(liste_locale)

Cutting the codes in the program and making it neater

I'm having a hard time cutting the code and making it into a loop so that it would make the code of the program, neater.
Although my code works as it suppose to be, I think there is a right way of creating it, adding a for loop rather than writing all of these codes, I know there is an easy way to do this, I just couldn't figure how to do it properly. I know I'm suppose to create a for loop.
squares
from graphics import *
def main():
win = GraphWin("Squares", 500, 500)
rect = Rectangle(Point(0,500), Point(500,0))
rect.setFill("Red")
rect.draw(win)
rect2 = Rectangle(Point(20,480), Point(480,20))
rect2.setFill("white")
rect2.draw(win)
rect3 = Rectangle(Point(40,460), Point(460,40))
rect3.setFill("red")
rect3.draw(win)
rect4 = Rectangle(Point(60,440), Point(440,60))
rect4.setFill("white")
rect4.draw(win)
rect5 = Rectangle(Point(80,420), Point(420,80))
rect5.setFill("red")
rect5.draw(win)
rect6 = Rectangle(Point(100,400), Point(400,100))
rect6.setFill("white")
rect6.draw(win)
rect7 = Rectangle(Point(120,380), Point(380,120))
rect7.setFill("red")
rect7.draw(win)
rect8 = Rectangle(Point(140,360), Point(360,140))
rect8.setFill("white")
rect8.draw(win)
rect9 = Rectangle(Point(160,340), Point(340,160))
rect9.setFill("red")
rect9.draw(win)
rect10 = Rectangle(Point(180,320), Point(320,180))
rect10.setFill("white")
rect10.draw(win)
rect11 = Rectangle(Point(200,300), Point(300,200))
rect11.setFill("red")
rect11.draw(win)
rect12 = Rectangle(Point(220,280), Point(280,220))
rect12.setFill("white")
rect12.draw(win)
The results shows squares into some sort of a patchwork
Try the following:
from graphics import *
def main():
win = GraphWin("Squares", 500, 500)
# create all rects
rects = [Rectangle(Point(0 + 20*i,500 - 20*i), Point(500 - 20*i, 0 + 20*i)) for i in range(12)]
# draw all rects
for idx, rect in enumerate(rects):
rect.fill("red" if idx % 2 == 0 else "white")
rect.draw(win)
If the patchwork is just a background and you don't plan on modifying it you could use this:
from graphics import *
def main():
win = GraphWin("Squares", 500, 500)
i = 1
for x in range(0, 221, 20):
rect = Rectangle(Point(x, 500 - x), Point(500 - x,x))
rect.setFill("red" if i % 2 else "white")
rect.draw(win)
i += 1
An alternate approach that only needs to draw half as many rectangles due to using the rectangle's outline as the other color:
SQUARE, WIDTH = 500, 20
def main():
win = GraphWin("Squares", SQUARE, SQUARE)
save_config = dict(DEFAULT_CONFIG)
DEFAULT_CONFIG.update(dict(outline='red', fill='white', width=WIDTH))
for xy in range(WIDTH//2, SQUARE//2, WIDTH*2):
Rectangle(Point(xy, SQUARE - xy), Point(SQUARE - xy, xy)).draw(win)
DEFAULT_CONFIG.update(save_config)
It's fully parameterized so you can fit it to a different size square or have different width stripes by adjusting the SQUARE and WIDTH parameters. Rather than draw 12 rectangles in alternating colors, with the parameters as currently set, it draws 6 white rectangles with red outlines:

Writing a mandelbrot set to an image in python

I am trying to write a mandelbrot set to an image in python, and am having a problem with one of my functions.
The issue is: While I expect something like this. I am getting a plain white image. Here is my code:
Quick Summary of code:
Check if value is in set, if it is, mark it as true in an array of booleans. Then, draw the image based on the array of booleans, coloring the true, and leaving the false ones.
import math
import numpy as np
import scipy.misc as smp
from PIL import PILLOW_VERSION
from PIL import Image
def iterate(x, y, iterationNum):
z = 0
coord = complex(x, y)
for a in xrange(iterationNum):
#Don't use fabs. It can be negative.
z = z * z + coord
#This is a comparison between complex and int. It probably won't work.
#You want |Z| which is: z.real ** 2 + z.imag ** 2 > 4
if math.fabs(z) > 2:
return False
return True
def pixel(image,x,y,r,g,b):
"""Place pixel at pos=(x,y) on image, with color=(r,g,b)"""
image.put("#%02x%02x%02x" % (r,g,b), (y, x))
#here's some example coloring code that may help:
def draw(grid):
#Create a white image with the size of the grid as the number of pixels
img = Image.new('RGB', (len(grid), len(grid)), "white")
pixels = img.load()
for row in xrange(len(grid)):
for col in xrange(len(grid[row])):
if grid[row][col] == True:
#If that point is True (it's in the set), color it blue
pixels[row, col] = (0, 0, 255)
return img
def mandelbrot():
#you should probably use a square, it's easier to deal with
#The mandelbrot set fits completely within (-2, 2) and (2, -2)
#(-200, 200), (200, -200) is way too big!
TopLeftX = -2; BottomRightX = 2
TopLeftY = 2; BottomRightY = -2
#increment should be calculated based on the size of the bounds and the number of pixels
#For example, if you're between -2 and 2 on the X-Plane, and your image is 400 pixels wide
#Then your increment = (2 - (-2)) / 400 = 4 / 400 = .01 so that each pixel is 1/400th of the
#Total width of the bounding area
increment = 0.01
maxIt = 100
w = BottomRightX - TopLeftX
h = TopLeftY - BottomRightY
#This should be based on the size of the image, one spot in the area for one pixel
npArr = np.zeros((w / increment, h / increment), dtype=bool)
#Use the increment variable from above. It won't work with xrange because that doesn't
#Support decimals. You probably want to use a while loop or something
x = -2
y = 2
while TopLeftX <= x <= BottomRightX:
while TopLeftY <= y <= BottomRightY:
#I recommend using True or False in here (in the set or not)
#And then do your color calculations as I explained above
#Saves a lot of memory
if iterate(x, y, maxIt):
npArr[x, y] = True
y += increment
#once you've calculated the Trues and Falses, you'd call the draw() function
#using the npArr as the parameter. I haven't tested the code, so there may
#be a few bugs, but it should be helpful!
x += increment
return npArr
img = draw(mandelbrot())
img.save("mandelbrot.png")
I suspect the problem is with the "iterate" function in my code, because none of the values i put in iterate are returning true.
EDIT
I have another issue as well, The second for loop I have here isnt even running.
Your handling of the y coordinate is faulty. You begin the outer loop with
y = 2
and have the loop condition as
while TopLeftY <= y <= BottomRightY:
After substituting their values, this is
while 2 <= y <= -2:
which is a nonsense. This is followed by
y += increment
but y is already at the top end of the range. Moreover, you fail to reset y for each inner loop.
To summarise, the loop should be
x = TopLeftX # use the value you already defined!
while TopLeftX <= x <= BottomRightX:
y = TopLeftY # moved to inside x loop
while TopLeftY >= y >= BottomRightY: # change the loop condition
# ... the Mandelbrot iteration
y -= increment # reverse direction
x += increment
I am no Python expert, so there may be other problems too.

Drawing a checkerboard in Python

I am trying to write a Python program which uses a graphics.py file and creates a checkerboard (like a chess board) with 64 squares alternating black and white. However, I am not able to get anything printed.
Here is my code so far. Please feel free to tear down the whole code or make any changes.
from graphics import GraphicsWindow
win = GraphicsWindow(400,400)
canvas = win.canvas()
for j in range(10, 90, 10):
for j in range(10, 90, 20):
if j % 2 == 1:
for i in 10, 30, 50, 70:
canvas.setFill("black")
canvas.drawRect(i, j, 10, 10)
else:
for i in 20, 40, 60, 80:
canvas.setFill("white")
canvas.drawRect(i, j, 10, 10)
You should be doing % 20 because your indices are multiples of 10.
Here's a simpler approach with one pair of nested loops:
offset_x = 10 # Distance from left edge.
offset_y = 10 # Distance from top.
cell_size = 10 # Height and width of checkerboard squares.
for i in range(8): # Note that i ranges from 0 through 7, inclusive.
for j in range(8): # So does j.
if (i + j) % 2 == 0: # The top left square is white.
color = 'white'
else:
color = 'black'
canvas.setFill(color)
canvas.drawRect(offset_x + i * cell_size, offset_y + j * cell_size,
cell_size, cell_size)
My go at it, in case may be usefull to someone:
import matplotlib.pyplot as plt
import numpy as np
def Checkerboard(N,n):
"""N: size of board; n=size of each square; N/(2*n) must be an integer """
if (N%(2*n)):
print('Error: N/(2*n) must be an integer')
return False
a = np.concatenate((np.zeros(n),np.ones(n)))
b=np.pad(a,int((N**2)/2-n),'wrap').reshape((N,N))
return (b+b.T==1).astype(int)
B=Checkerboard(600,30)
plt.imshow(B)
plt.show()

Categories