Drawing a checkerboard in Python - 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()

Related

ListIndex out of range, not sure why?

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

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)

Creating a pattern using Python Graphics Module

I'm trying to draw a specific pattern in a 100x100 window using the John Zelle’s graphics module, however I'm struggling to reach the intended pattern. I am sure of the increments and the range, in fact I get the first column right however the the others are stuck together and I can’t find what I did wrong. Any thoughts?
Here is the code:
def pattern1():
win = GraphWin("Rec",100,100)
x=0
y=10
x2=20
y2=10
for i in range(4):
for j in range(3):
r = Rectangle(Point(x,1), Point(y,100))
r.setFill("Red")
r.setOutline("Red")
r.draw(win)
r2 = Rectangle(Point(1,x2), Point(100,y2))
y=y+10
x2=x2+20
x=0
x=x+20
y2=y2+20
This is the pattern I'm trying to do:
I see two separated parts which need separated for-loops: vertical lines and horizontal lines.
from graphics import *
def pattern():
win = GraphWin("Rec", 100, 100)
# vertical lines
for x in range(0, 100, 40):
r = Rectangle(Point(x, 0), Point(x+20, 100))
r.setFill("Red")
r.setOutline("Red")
r.draw(win)
# horizontal lines
for y in range(20, 100, 40):
r = Rectangle(Point(0, y), Point(100, y+20))
r.setFill("Red") # "Green"
r.setOutline("Red") # "Green"
r.draw(win)
pattern()
Using different colors then you can see
If you draw first horizontal lines then you can see
Sometimes, it's easier to draw what isn't there than what is:
from graphics import *
def pattern():
for y in range(0, 100, 40):
for x in range(20, 100, 40):
r = Rectangle(Point(x, y), Point(x+20, y+20))
r.setFill("White")
r.setOutline("White")
r.draw(win)
win = GraphWin("Rec", 100, 100)
win.setBackground('Red')
pattern()

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:

How can I make a start on re-writing this Python homework code?

Here is my homework:
Edit this code to make sure the parameters reflect the super rectangle (for example rows = 6 and squares = 60, the super rectangle will have 6 rows of 10 squares.)
Here is the code:
import turtle
import time
bob = turtle.Turtle()
def make_square(bob, length):
for x in range(4):
bob.rt(90)
bob.fd(length)
def super_rectangle(bob, rows=2, squares=4, length=100):
height = (length / rows)
columns = int(squares / rows)
for row in range(rows):
for column in range(columns):
bob.fd(length)
make_square(bob, length)
bob.rt(90)
bob.fd(length * 2)
bob.rt(90)
time.sleep(1)
super_rectangle(bob, length=100)
It's not clear to me what exactly the OP is asking. However, running the code, it's clear it's faulty as the case mentioned in the objective section:
e.g. rows = 6 and squares = 60, then your super rectangle will have 6
rows of 10 squares.
Doesn't work. When you invoke super_rectangle(bob, 6, 60, 30), after fixing code indentation, you get:
being overdrawn mutliple times. We can put a band-aid on (and clean up) the OP's code to fix the situation:
from turtle import Screen, Turtle
def make_square(turtle, length):
for _ in range(4):
turtle.left(90)
turtle.forward(length)
def super_rectangle(turtle, rows=2, squares=4, length=100):
columns = squares // rows
parity = 1
for row in range(rows):
for _ in range(columns):
turtle.forward(length)
make_square(bob, length)
turtle.right(parity * 90)
if parity < 1 and row < rows - 1:
turtle.forward(length * 2)
turtle.right(parity * 90)
parity = 0 - parity
screen = Screen()
bob = Turtle()
bob.speed('fastest') # because I have no patience
super_rectangle(bob, 6, 60, 30)
screen.exitonclick()
Which draws the described output:
But if we take the OP's title literally:
Different way to re-write this python code?
Then I suggest that stamping, rather than drawing, is the right way to handle this problem. This approach makes the code simpler and faster:
from turtle import Screen, Turtle
CURSOR_SIZE = 20
def super_rectangle(turtle, rows=2, squares=4, length=100):
columns = squares // rows
turtle.shapesize(length / CURSOR_SIZE)
parity = 1
for _ in range(rows):
for _ in range(columns):
turtle.stamp()
turtle.forward(parity * length)
x, y = turtle.position()
turtle.setposition(x + -parity * length, y + length)
parity = 0 - parity
screen = Screen()
bob = Turtle('square', visible=False)
bob.color("black", "white")
bob.penup()
super_rectangle(bob, 6, 60, 30)
screen.exitonclick()
I need to really draw not stamping.
We can implement this a completely different way using drawing that's simpler and far more efficient than your patched code. The key is to address the extensive redundancy in the drawing. Instead of drawing individual squares, we'll put up all the horizonal lines and then all the vertical lines:
from turtle import Screen, Turtle
def make_serpentine(turtle, length, rows, columns, parity=1):
for _ in range(rows):
turtle.forward(length * columns)
turtle.left(parity * 90)
turtle.forward(length)
turtle.left(parity * 90)
parity = 0 - parity
def super_rectangle(turtle, rows=2, squares=4, length=100):
columns = squares // rows
make_serpentine(turtle, length, rows, columns)
turtle.forward(length * columns)
turtle.right(90)
make_serpentine(turtle, length, columns, rows, -1) # reverse sense of rows & columns
turtle.forward(length * rows)
turtle.left(90) # leave things as we found them
screen = Screen()
bob = Turtle()
super_rectangle(bob, 6, 60, 30)
screen.exitonclick()

Categories