Creating a pattern using Python Graphics Module - python

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

Related

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:

Random Line Generation For pygame

My goal is to make a retro lunar lander game using pygame. Right now I'm trying to create the background of mountains and platforms to land on. I would like for every time a new game is started the platforms and mountains be different. My idea is to draw a random number of horizontal lines with random lengths as the platform. I have a few problems with this:
How to make sure the horizontal lines don't overlap and are all accesible in regards of looking at it like you're landing.
I think the best way to draw the mountains would be to connect the platforms with more lines that create triangles, but I have no idea where to begin to do that
the code I have been working for currently generates random lines, but I'm not sure how to develop the code further.
for platforms in range(1, random.randint(1, 10)):
rand_x_start = random.randint(0, 400)
rand_x_end = random.randint(0, 400)
rand_y = random.randint(HEIGHT / 2, HEIGHT)
pygame.draw.line(self.background, white, (rand_x_start, rand_y), (rand_x_end, rand_y), 2)
I've tried looking through many questions and tutorials about random generation, but none are remotely close to what I'm looking for.
A thought I had to fix the overlapping problem was if there was a way to "read" or "see" previously created lines and to limit drawing based on that some how...but I'm not sure of a way to do that.
I put together the following code as something that might help you out:
import random
from collections import namedtuple
from PIL import Image, ImageDraw
GaussianDistribution = namedtuple('GaussianDistribution', ['mu', 'sigma'])
Platform = namedtuple('Platform', ['start', 'end', 'height'])
Point = namedtuple('Point', ['x', 'y'])
PLATFORM_HEIGHT_DISTRIBUTION = GaussianDistribution(50, 10)
PLATFORM_WIDTH_DISTRIBUTION = GaussianDistribution(100, 10)
INTER_PLATFORM_DISTRIBUTION = GaussianDistribution(500, 20)
RANDOM = random.Random()
def sample_distribution(distribution):
return RANDOM.normalvariate(distribution.mu, distribution.sigma)
def create_platforms(num_platforms):
last_platform_end = 0
for i in range(num_platforms):
start = int(sample_distribution(INTER_PLATFORM_DISTRIBUTION) + last_platform_end)
end = int(sample_distribution(PLATFORM_WIDTH_DISTRIBUTION) + start)
height = int(sample_distribution(PLATFORM_HEIGHT_DISTRIBUTION))
last_platform_end = end
yield Platform(start, end, height)
def create_mountains_between_points(p1, p2):
mountain_start = p1.x
mountain_end = p2.x
num_points = int((mountain_end - mountain_start) / 10)
for i in range(num_points):
# TODO: use 1D Perlin function to generate point.y
yield Point(mountain_start + i * 10, RANDOM.random() * 100)
def create_terrain(platforms):
origin = Point(0, 0)
first_platform_start = Point(platforms[0].start, platforms[0].height)
terrain = []
terrain += list(create_mountains_between_points(origin, first_platform_start))
for i, platform in enumerate(platforms):
platform_starts_at = Point(platform.start, platform.height)
platform_ends_at = Point(platform.end, platform.height)
terrain.append(platform_starts_at)
terrain.append(platform_ends_at)
if i < len(platforms) - 1:
next_platform = platforms[i + 1]
next_platform_starts_at = Point(next_platform.start, next_platform.height)
mountains = create_mountains_between_points(platform_ends_at, next_platform_starts_at)
terrain += mountains
return terrain
def draw_terrain(terrain):
im = Image.new('RGBA', (4000, 200), (255, 255, 255, 0))
draw = ImageDraw.Draw(im)
draw.line(terrain, fill=(0, 0, 0, 255))
im.show()
if __name__ == '__main__':
platforms = list(create_platforms(num_platforms=10))
terrain = create_terrain(platforms)
draw_terrain(terrain)
This generates the following terrain. You can see that there are flat areas (platforms) separated by mountains. Platforms are guaranteed not to overlap. They are also guaranteed to be "accessible" in that there will never be any terrain generated over them.
I generate the y ordinates for the mountains by sampling from a uniform distribution. You can probably make the mountains look better by using the Perlin noise algorithm I mentioned earlier. I found this attempt to use Perlin noise in a pygame application.

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

Replicating this design in Python

I've been trying to replicate this design using Python.
I am using the Graphics module, obtained here. I can't use any other Graphic Module at the moment.
This code here allows me to draw 5 circles in a line repeated by a loop.
def fdShape():
win = GraphWin(199,199)
centre = Point(20,100)
for y in range(5):
for x in range(5):
centre = Point(x * 40 + 20, y * 40 + 60)
circle = Circle(centre, 20)
circle.setOutline("red")
circle.draw(win)
One problem that I've found with this code is that it leaves a blank line at the top of the window and place the last circle line at the bottom, beyond the borders of the window. Thats the first problem.
The second is using the code to display semi circles displayed in red. As you can see in the image at the top of this page. I'm unsure of how to replicate this picture using Python.
Thank you!
This looks pretty close:
from graphic import *
def main():
repeat = 5
diameter = 40
radius = diameter // 2
offset = radius // 2
win = GraphWin("Graphic Design", diameter*repeat + offset, diameter*repeat)
win.setBackground('white')
for i in range(repeat):
for j in range(repeat):
draw_symbol(win, i % 2,
Point(i*diameter + offset, j*diameter), radius, 'red')
win.getMouse()
win.close()
def draw_symbol(win, kind, lower_left, radius, colour):
centre = Point(lower_left.x+radius, lower_left.y+radius)
circle = Circle(centre, radius)
circle.setOutline('')
circle.setFill(colour)
circle.draw(win)
if kind == 0:
rectangle = Rectangle(lower_left,
Point(lower_left.x+radius, lower_left.y+radius*2))
else:
rectangle = Rectangle(lower_left,
Point(lower_left.x+radius*2, lower_left.y+radius))
rectangle.setOutline('white')
rectangle.setFill('white')
rectangle.draw(win)
circle = Circle(centre, radius)
circle.setWidth(1)
circle.setOutline(colour)
circle.setFill('')
circle.draw(win)
main()
Two issues I see.
GraphWin should be initialized to 200x200, not 199x199.
This line:
centre = Point(x * 40 + 20, y * 40 + 60)
Should most likely be:
centre = Point(x * 40 + 20, y * 40 + 20)

Loop patchwork in python3

I need to create a patchwork in Python 3. All I have left to do is create a loop which makes the design border the graphics window. I know I need a for loop however I am not sure how to do this.
This is what I have so far:
from graphics import *
def main():
height = eval(input("What is the height of the window"))
width = eval(input("What is the width of the window"))
colour = input("enter the colour of the patch")
win = GraphWin("Patch", 100*width, 100*height)
boat_x = 0
boat_y = 0
for x in range (4):
boat(win, boat_x, boat_y, colour)
boat_x = boat_x + 23
for i in range(height * 5):
boat(win, boat_x, boat_y, colour)
boat_x = boat_x + 24
for j in range(height * 5):
boat(win, boat_x, boat_y, colour)
boat_y = boat_y + 100
win.getMouse()
win.close()
def boat(win, x, y, colour):
body1 = Polygon(Point(1+x,95+y), Point(5+x,100+y),
Point(20+x,100+y), Point(24+x,95+y))
body1.draw(win)
line1 = Line(Point(13+x,95+y), Point(13+x,90+y))
line1.draw(win)
sail1 = Polygon(Point(1+x,90+y), Point(24+x,90+y), Point(13+x, 73+y))
sail1.setFill(colour)
sail1.draw(win)
body2 = Polygon(Point(1+x, 63), Point(5+x, 68),
Point(20+x,68), Point(24+x,63))
body2.draw(win)
line2 = Line(Point(13+x,63), Point(13+x,58))
line2.draw(win)
sail2 = Polygon(Point(1+x,58), Point(24+x, 58), Point(13+x,40))
sail2.setFill(colour)
sail2.draw(win)
body3 = Polygon(Point(1+x,28), Point(5+x,33),
Point(20+x,33), Point(24+x, 28))
body3.draw(win)
line3 = Polygon(Point(13+x,28), Point(13+x,23))
line3.draw(win)
sail3 = Polygon(Point(1+x,23), Point(24+x, 23), Point(13+x, 5))
sail3.setFill(colour)
sail3.draw(win)
main()
So far this creates the top border but nothing else.
I am also aware that the boat function isn't the most efficient way of drawing
When you say that you need to "make the design border the graphics window" I assume you want your boat design to be repeated several times along each edge of the window (that is, the top, bottom, left and right).
This should be doable in two loops. One will draw the top and bottom edges, the other two will draw the left and right edges. I'm not too sure how your drawing code works, so I'm guessing at some offsets here:
top = 0
bottom = (height-1) * 100
for x in range(0, width*100, 25):
boat(x, top, colour)
boat(x, bottom, colour)
left = 0
right = width * 100 - 25
for y in range(100, (height-1)*100, 100):
boat(left, y, colour)
boat(right, y, colour)
This should call your boat subroutine every 25 pixels across the top and bottom, and every 100 pixels along the left and right edges. Adjust the top, bottom, left and right values and the parameters in the range calls in the loops to make the spacing suit your needs (I just made it up). This code avoids drawing the corner items twice, though depending on how the drawing routine works that might not be necessary.

Categories