Add multiple choice score - python

I need to add up the score in a multiple choice quiz.
This is my code:
from tkinter import *
import time, os, random
global questions
questions = []
questions = ['''
What does ? equal to:
43+(5x(6)**8)/8-8+8 = ?
1) 10356
2) 1049803
3) 202367
4) 12742130
5) 343321
''',
'''
Find the range, the median, the mode and the mean:
>>> 232, 4343, 434, 232.4, 43, 5453, 434, 232, 645, 23.3, 53453.3, 434 <<<
1) 53410.3, 2943.5, 434, 5496.58
2) 53410.3, 5956, 434, 5453.28
3) 232, 43, 3452, 421, 642
4) 232, 43, 43, 434
5) 232, 5453, 645, 53453.3
''',
'''
In 2004, the minimum wage in Ontario was $7.15.
In 2008, it was $8.15. What is the rate of change?
1) $0.90
2) $3.98
3) $1.54
4) $0.40
5) $1.80
''',
'''
Find the value of n:
--------------------------------------
43n/2n x (99.99/9)x7 = 99.99n
--------------------------------------
1) n = 99.92
2) n = 12.43
3) n = 16.73
4) n = 104.4
5) n = 3.98
''',
'''
Which one is NOT a linear equation?
1) y = 54x*3
2) y = 23x*7
3) y = -x
4) All of the Above
5) None of the Above
''',
'''
What is the formula for finding the surface area for a sphere?
1) 4/3πr**3
2) πr**2
3) 2πrh + 2πr**2
4) πd
5) 4πr**2
''',
'''
Which variable represents the slope?
y = mx + c
1) y
2) m
3) x
4) c
5) None of the above
''',
'''
An isosceles triangle has the top angle of 6x
and a supplementary angle of a base angle is 21x. What are the
measures of the angles of isosceles triangle?
1) 22.5, 78.75, 78.75
2) 108.97, 35.52, 35.52
3) 76.8, 51.6, 51.6
4) 20, 20, 140
5) 43.6, 5.5, 98.53
''',
'''
A sphere fits inside a rectangular box of 6cm by 6cm by 7cm.
What is the greatest possible volume of the sphere?
1) 113.04 cm*2
2) 110.46 cm*3
3) 113.04 cm*3
4) 110.46 cm*2
5) 142.9 cm*3
''',
'''
If the area of an isosceles triangle is 196 cm**2
and the height is 19.6 cm, what would it's perimeter be?
1) 53.9 cm
2) 64 cm
3) 76 cm
4) 32.43 cm
5) 32.32 cm
'''
]
global answers
global picked
global userans
global ansRandOrder
global score
answers = ['2', '1', '4', '3', '5', '5', '2', '1', '3', '2']
picked = []
userans = []
ansRandOrder = []
score = 0
def nexT():
global userans
userans.append(e1.get())
print(userans)
print(ansRandOrder)
global score
global i
i = 0
if userans[i] == ansRandOrder[i]:
score += 1
i += 1
print(score)
self.destroy()
ques()
def ques():
global self
global e1
global ansRandOrder
global picked
self = Tk()
w = 500
h = 375
ws = self.winfo_screenwidth()
hs = self.winfo_screenheight()
x = (ws/2) - (w/2)
y = (hs/2) - (h/2)
self.geometry('%dx%d+%d+%d' % (w, h, x, y))
x = random.randint(0, 9)
while x in picked:
x = random.randint(0, 9)
picked.append(x)
ansRandOrder.append(answers[x])
Label(self, text = '\n').pack()
Label(self, text = questions[x]).pack()
e1 = Entry(self)
e1.pack()
Label(self, text = '\n').pack()
nex = Button(self, text = 'Next Question', command = nexT).pack()
self.mainloop()
ques()
The result is always score = 0.
How can I correctly add the score?

I've experimented a bit with your code and the issue seems to lie elsewhere. For some reason or another the script always compares the wrong answers for the if in nexT. Other times, after restarting the script without clearing old variables, it always thinks the answer is correct.
I think this issue will probably go away if you clean up your code a bit. I'd recommend you rewrite your code as a class, which is a common approach to Tkinter scripts. The main advantages for you would be:
It's a lot more readable (It'll be easier to debug)
No more global variables, instead you just refer to the variables as part of the class (self.variable)
When the program exits (which it doesn't seem to do properly at the moment) you can just finish with something like del MyClass to get rid of the variable clutter. That clutter is probably why the behaviour of this bug changes from time to time.
Have a look at this thread for some good examples and explanations about building a tkinter class-based application:
Best way to structure a tkinter application
As an example for your quiz, it might look something like this: (Non-functional)
class Quiz():
def __init__(self):
self.questions = []
self.WriteQuestions()
self.answers = ['2', '1', '4', '3', '5', '5', '2', '1', '3', '2']
self.picked = []
self.userans = []
self.ansRandOrder = []
self.score = 0
#"self." instead of "global"
# Any def inside this class can refer to self."variable" and use it or update it.
self.Question()
def WriteQuestions(self):
# All your questions here, just so they're out of the way.
def NextQuestion(self):
self.userans.append(e1.get())
self.i = 0
if self.userans[i] == ansRandOrder[i]:
self.score += 1
i += 1
print(self.score)
root.destroy() # You'll need to pick a name other than "self" for your tk window
self.Question()
# self is a reserved keyword for classes and shouldn't be used for anything other
# than telling a class that you're referring to one of its own variables or functions.
def Question(self):
# etc...
if __name__ == 'main':
# set up tkloop here
# create an instance of the Quiz class, e.g.
Qz = Quiz()
# finally, after the loop finishes:
del Qz # To get rid of the old variables

Related

PyOpenGL code with vbos for rendering tile-based game creating blank screen

I have been, with pygame and pyopengl (oh and obviously Python), been trying to make a little tile-based 2D game, but I'm having trouble with the rendering using VBOs and glMultiDrawArray().
The program runs without errors, but I don't see any geometry drawn, so it's just a blank screen.
I've tried using glTranslate to see if maybe the geometry is being drawn, but I can't see it, as well as changing between using GluPerspective() and glOrthro2D(). No luck. I've pored over the code to see where it isn't working, but I have no clue what could be wrong. I'm still struggling to understand OpenGL and VBOs.
Here are the relevant bits of my code:
The Chunk class. Every chunk has its own VBO for vertices and textures (textures are currently unused)
class Chunk():
def __init__(self, position):
self.Position = position
self.VertexVBOId = _get_chunk_id()
self.VertexVBO = glGenBuffers(self.VertexVBOId)
self.TextureVBOId = _get_chunk_id()
self.TextureVBO = glGenBuffers(self.TextureVBOId)
Chunks[str(position)] = self
self.__updateVertexArray()
# glBindBuffer (GL_ARRAY_BUFFER, self.VertexVBO)
#self.__updateVertexArray()
def __getvertices(self):
vertices = []
for x in range(self.Position.x, self.Position.x + 16):
for y in range(self.Position.y, self.Position.y + 16):
pos = Vector2(x, y)
tile = GetTile(pos)
if tile != "air":
vertices.append(x+1)
vertices.append(y)
vertices.append(x+1)
vertices.append(y+1)
vertices.append(x)
vertices.append(y+1)
vertices.append(x)
vertices.append(y)
return vertices
def __updateVertexArray(self): #This will be called when a change is made the the chunk, as well as once initially
print("UPDATING VERTEX ARRAY")
vertices = self.__getvertices()
glBindBuffer (GL_ARRAY_BUFFER, self.VertexVBOId)
glBufferData (GL_ARRAY_BUFFER, len(vertices)*4, (c_float*len(vertices))(*vertices), GL_DYNAMIC_DRAW)
And here is the rendering loop:
def main():
print("Started")
pygame.init()
global displaySize
global SCREENSIZE
global PIXELS_PER_TILE
pygame.display.set_mode(displaySize, DOUBLEBUF|OPENGL)
#gluOrtho2D(-SCREENSIZE[0]/2, SCREENSIZE[0]/2, -SCREENSIZE[1]/2, SCREENSIZE[1]/2)
gluPerspective(180, 2, 0.1, 100)
... some other stuff ...
while True:
#Drawing
glClearColor(0.7, 0.7, 1, 0)
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)
cameraTranslateX = (camera.Position.x % 1) * PIXELS_PER_TILE
cameraTranslateY = (camera.Position.y % 1) * PIXELS_PER_TILE
#Figure out which chunks to render
botLeft = camera.Position - Vector2(SCREENSIZE[0]/2, SCREENSIZE[1]/2) + Vector2(cameraTranslateX, cameraTranslateY)
topRight = camera.Position + Vector2(SCREENSIZE[0]/2, SCREENSIZE[1]/2) + Vector2(cameraTranslateX, cameraTranslateY)
FirstChunkPos = (botLeft/16).floor()
TotalChunksX = (topRight/16).ceil().x - FirstChunkPos.x
TotalChunksY = (topRight/16).ceil().y - FirstChunkPos.y
for x in range(TotalChunksX):
for y in range(TotalChunksY):
pos = Vector2(x + FirstChunkPos.x, y + FirstChunkPos.y)
chunk = Chunks.get(str(pos))
if not chunk:
chunk = Chunk(pos)
VertexVBO = chunk.VertexVBOId
glBindBuffer (GL_ARRAY_BUFFER, VertexVBO)
glVertexPointer (2, GL_FLOAT, 0, None)
TextureVBO = chunk.TextureVBOId
glMultiDrawArrays (GL_POLYGON, vertexArrayThingy1, vertexArrayThingy2, 255)
# glUnmapBuffer(GL_ARRAY_BUFFER,VertexVBO)
pygame.display.flip ()
The 2nd and 3rd arguments of glMultiDrawArrays are of type const GLint* and const GLsizei*. This function cannot draw from different buffers. There is no glDraw* command that can use multiple vertex buffers for drawing. All vertecx attributes must be in one and the same buffer. glMultiDrawArrays should draw different ranges from the buffer. Suppose you want to draw the following 3 attribute ranges [3:6], [18:27], [30:36]:
first = [3, 18, 30]
count = [3, 9, 6]
glMultiDrawArrays(GL_TRIANGLES, first, count, 3)
If you want to draw multiple lists of indices you have to use glMultiDrawElements and you have to create an array of pointers to arrays of indices:
import ctypes
ia1 = (GLuint * 6)(0, 1, 2, 0, 2, 3)
ia2 = (GLuint * 6)(12, 13, 14, 12, 14, 15)
counts = [6, 6]
indexPtr = (GLvoidp * 2)(ctypes.addressof(ia1), ctypes.addressof(ia2))
glMultiDrawElements(GL_TRIANGLES, counts, GL_UNSIGNED_INT, indexPtr, 2)

How to move points of a line to specific locations?

I'm trying visualise the sine waves addition in python using tkinter, and I'm trying to build lines between each circles center, but what I've tried so far didnt work as I thought it would. is there a way to fix what I've tried (see code), or a way to move only one coordinates point of a line independantly from the other?
As you'll see in the code if you run it, I've tried a method where each iteration the previous line is erased and a new one is created. When I run the code there is actually a line between each center of the circles just like I want, but facts are those lines persist and won't erase themselves; for some reason it seems like the canvas.delete(line) doesnt work as I expected it to.
here's the full code. The interesting part is in the 'updateline' fonction, into 'act()' func.
import math
import tkinter as tk
##important to know! -- the way I'm creating the circles is by setting an object, the bounds of the circle, depending on amplitude asked by user.
##then the programs calculates the path of these bounds, depending on circles, amplitude, phase and frequency of the sine waves asked by the user from the tkinter GUI.
##finally, the program creates and moves along this path a circle, representing visually the sine wave.
top = tk.Tk()
top.title('Superposition')
choice = tk.Tk()
choice.title('Parametres')
f = tk.Frame(choice,bd=3)
f.pack(side='top')
g = tk.Frame(choice,bd=3)
g.pack(side='bottom')
tk.Label(f,text="nbre ondes:",width = 10).grid(row=0,column=0)
sines = tk.Spinbox(f,from_=1,to=50,width=10,textvariable=tk.DoubleVar(value=2))
sines.grid(row=0,column=1)
sines.delete(0,5)
sines.insert(0,2)
delai = tk.Scale(g, orient='vertical', from_=100, to=1,resolution=1, length=100,label='delai')
delai.grid(row=0,column=0)
hauteur = tk.Scale(g, orient='vertical', from_=1100, to=100,resolution=100, length=100,label='fenetre')
hauteur.grid(row=0,column=1)
taillec1 = tk.Scale(g, orient='vertical', from_=3.5, to=0.1,resolution=0.1, length=100,label='taille')
taillec1.grid(row=0,column=2)
delai.set(20)
hauteur.set(600)
taillec1.set(1.5)
def grilledechoix():
numberofsines = int(sines.get())
for i in f.grid_slaves():
if int(i.grid_info()["row"]) > numberofsines+2:
i.grid_forget()
for i in range(1,numberofsines+1):
tk.Label(f,text="phase n."+str(i),width = 10).grid(row=i+2,column=4)
phase = tk.Spinbox(f,from_=-180,to=180,width=10)
phase.grid(row=i+2,column=5)
phase.delete(0,5)
phase.insert(0, 0)
for i in range(1,numberofsines+1):
tk.Label(f,text="amp. n."+str(i),width = 10).grid(row=i+2,column=0)
ampli = tk.Spinbox(f,from_=1,to=10000000,width=10)
ampli.grid(row=i+2,column=1)
ampli.delete(0,5)
ampli.insert(0,10)
for i in range(1,numberofsines+1):
tk.Label(f,text="freq n."+str(i),width = 10).grid(row=i+2,column=2)
freq = tk.Spinbox(f,from_=-1000,to=1000,width=10)
freq.grid(row=i+2,column=3)
freq.delete(0,5)
freq.insert(0,5)
def act():
h = g.grid_slaves()[1].get()
delai = g.grid_slaves()[2].get()
taillec1 = g.grid_slaves()[0].get()
w = h
ampdict = {'box1':100 * ((h/700)*taillec1)}
frqdict = {}
aaadict = {}
fffdict = {}
phadict = {}
numberofsines = int(sines.get())
sin = lambda degs: math.sin(math.radians(degs))
cos = lambda degs: math.cos(math.radians(degs))
for i in range(1,numberofsines+1):
fffdict['box'+str(numberofsines-i+1)] = f.grid_slaves()[(2*i)-2].get()
aaadict['box'+str(numberofsines-i+1)] = f.grid_slaves()[(2*i)-2+2*numberofsines].get()
phadict['box'+str(numberofsines-i+1)] = f.grid_slaves()[(2*i)-2+4*numberofsines].get()
for i in range(1,numberofsines+1):
ampdict['box'+str(i)] = (float(ampdict['box1'])/float(aaadict['box1'])) * float(aaadict['box'+str(i)])
frqdict['box'+str(i)] = float(fffdict['box'+str(i)])/float(fffdict['box1'])
class obj(object):
cos0, cos180 = cos(0), cos(180)
sin90, sin270 = sin(90), sin(270)
def __init__(i, x, y, rayon):
i.x, i.y = x, y
i.rayon = rayon
def bounds(i):
return (i.x + i.rayon*i.cos0, i.y + i.rayon*i.sin270,
i.x + i.rayon*i.cos180, i.y + i.rayon*i.sin90)
def updateposition(canvas, id, cent, obj, path):
obj.x, obj.y = next(path)
x0, y0, x1, y1 = canvas.coords(id)
oldx, oldy = (x0+x1) // 2, (y0+y1) // 2
dx, dy = obj.x - oldx, obj.y - oldy
canvas.move(id, dx, dy)
canvas.move(cent, dx, dy)
canvas.after(delai, updateposition, canvas, id, cent, obj, path)
def updateline(canvas, line, robj0, cent0, robj1, cent1):
x00, y00, x01, y01 = canvas.coords(cent0) ##defining coords of the two ovals asked, representing centers of circles
x10, y10, x11, y11 = canvas.coords(cent1)
oldx0, oldy0 = (x00+x01) // 2, (y00+y01) // 2 ##defining center coords of the two ovals
oldx1, oldy1 = (x10+x11) // 2, (y10+y11) // 2
dx0, dy0 = robj0.x - oldx0, robj0.y - oldy0 ##defining the deltax and deltay, difference of movements between frames, of the two ovals
dx1, dy1 = robj1.x - oldx1, robj1.y - oldy1
canvas.after(delai, canvas.delete, line) ##deleting previous line, does not work and I don't know why. I've also tried 'canvas.delete(line)', giving same results
canvas.create_line(oldx0+dx0, oldy0+dy0, oldx1+dx1, oldy1+dy1) ##creating new line
canvas.after(delai, updateline, canvas, line, robj0, cent0, robj1, cent1) ##function invoking itself after delay 'delai'
def posobj(pt,ang,deltang):
while True:
yield pt.x + pt.rayon*cos(ang), pt.y + pt.rayon*sin(ang)
ang = (ang+deltang)%360
try:
top.pack_slaves()[0].destroy()
except:
pass
canvas = tk.Canvas(top, bg='white', height=h, width=w)
canvas.pack(side='right')
robj = {}
r = {}
posobjet = {}
line = {}
cent = {}
## the following 'for' loop creates a number of circles corresponding to sine waves, as much as the user asked.
for i in range(1,int(sines.get())+2):
if i != int(sines.get())+1:
if i == 1:
robj[str(i)] = obj(h/2,h/2,float(ampdict['box'+str(i)]))
r[str(i)] = canvas.create_oval(robj[str(i)].bounds(),fill='',outline='black')
cent[str(i)] = canvas.create_oval(h/2+h/200,h/2+h/200.,h/2-h/200,h/2-h/200, fill='white', outline='red')
posobjet[str(i)] = posobj(robj[str(i)],float(phadict['box'+str(i)]),float(frqdict['box'+str(i)]))
else:
robj[str(i)] = obj(robj[str(i-1)].x,robj[str(i-1)].y,float(ampdict['box'+str(i)]))
r[str(i)] = canvas.create_oval(robj[str(i)].bounds(),fill='',outline='black')
cent[str(i)] = canvas.create_oval(robj[str(i)].x+h/200,robj[str(i)].y+h/200,robj[str(i)].x-h/200,robj[str(i)].y-h/200, fill='white', outline='blue')
line[str(i)] = canvas.create_line(0,0,0,0)
posobjet[str(i)] = posobj(robj[str(i)],float(phadict['box'+str(i)]),float(frqdict['box'+str(i)]))
top.after(delai, updateposition, canvas, r[str(i)], cent[str(i)], robj[str(i)], posobjet[str(i-1)])
##here I'm invoking the updateline function using the constant 'delai', the line i, and objects defining the bounds of the center objects, the little blue/red dots appearing as the center of each circles(run the code, it'll be easier to understand)
top.after(delai, updateline, canvas, line[str(i)], robj[str(i-1)], cent[str(i-1)], robj[str(i)], cent[str(i)])
else:
robj[str(i)] = obj(robj[str(i-1)].x,robj[str(i-1)].y,h/200)
r[str(i)] = canvas.create_oval(robj[str(i)].bounds(),fill='white',outline='red')
cent[str(i)] = canvas.create_oval(robj[str(i)].x+h/200,robj[str(i)].y+h/200,robj[str(i)].x-h/200,robj[str(i)].y-h/200, fill='white', outline='red')
line[str(i)] = canvas.create_line(0,0,0,0)
top.after(delai, updateposition, canvas, r[str(i)], cent[str(i)], robj[str(i)], posobjet[str(i-1)])
##2nd and last time invoking the updateline function, for the line between the last circle's point and the final red point.
top.after(delai, updateline, canvas, line[str(i)], robj[str(i-1)], cent[str(i-1)], robj[str(i)], cent[str(i)])
top.mainloop()
ok = tk.Button(f,text='NBRE',command=grilledechoix)
ok.grid(row=0,column=2)
ac = tk.Button(f,text='APPLY',command=act)
ac.grid(row=0,column=3)
grilledechoix()
act()
I expected the lines to disappear once the updateline function called itself again, because of that 'canvas.delete(line)' line into updateline, and I can't really understand why it does that.
anyway if you have a solution to make the lines move, without creating and deleting them each time the function is called, feel free to tell me.
Thanks!
If I understand the problem correctly, I believe the issue is with this code:
canvas.after(delai, canvas.delete, line)
canvas.create_line(oldx0+dx0, oldy0+dy0, oldx1+dx1, oldy1+dy1)
canvas.after(delai, updateline, canvas, line, robj0, cent0, robj1, cent1)
It fails to reassign the new line to the line variable for the next call. Instead try:
canvas.after(delai, canvas.delete, line)
line = canvas.create_line(oldx0+dx0, oldy0+dy0, oldx1+dx1, oldy1+dy1)
canvas.after(delai, updateline, canvas, line, robj0, cent0, robj1, cent1)
Which gets rid of the extra lines when I run it. Let me know if I've missed the point.

How to draw a random triangle and its median? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I want to draw a triangle like this:
I have tried different ways of solving it, but I have not done it correctly. How to add median lines in the triangle? Could someone please help and explain this to me?
from turtle import *
import random
def allTriMedian (w=300):
speed (0)
vertices = []
point = turtle.Point(x,y)
for i in range (3):
x = random.randint(0,300)
y = random.randint(0,300)
vertices.append(trutle.Point(x,y))
point = turtle.Point(x,y)
triangle = turtle.Polygon(vertices)
a = triangle.side()
b = triangle.side()
c = triangle.side()
m1 = tirangle.median
m2 = triangle.median
m3 = triangle.median
I tried to put the equation directly
def Median (a, b, c):
m1 = sqrt((((2b^2)+(2c^2)-(a^2))))
m2 = sqrt((((2a^2)+(2c^2)-(b^2))))
m3 = sqrt((((2a^2)+(2b^2)-(c^2))))
triangle.setFill("yellow")
triangle.draw(allTriMedian)
Or I thought to find a midpoint and draw a line segment to connect the vertices and midpoints.
def getMid(p1,p2):
return ( (p1[0]+p2[0]) / 2, (p1[1] + p2[1]))
mid1 = Line((point(p1[0]+p2[0]) / 2),point(x))
mid2 = Line((point(p2[1]+p3[1]) / 2),point(y))
I hate doing math. Let's see if we can solve this by throwing turtles at the problem. Lots of turtles.
We'll randomly generate the verticies of the triangle. Taking pairs of verticies in turn, we'll start a turtle at each heading toward the other. When the turtles collide (at the midpoint), we'll eliminate one turtle and send the other toward the vertex not in the pair. Once we've done this three times (with six turtles), we should have the drawing in question. Well, mostly (no fill in my solution):
from turtle import Turtle, Screen
from random import seed, randint
WIDTH, HEIGHT = 640, 480
def meet_in_the_middle(turtle_1, turtle_2):
position_2 = turtle_2.position()
while True:
turtle_1.setheading(turtle_1.towards(turtle_2))
turtle_1.forward(1)
position_1 = turtle_1.position()
if int(position_1[0]) == int(position_2[0]) and int(position_1[1]) == int(position_2[1]):
break
turtle_2.setheading(turtle_2.towards(turtle_1))
turtle_2.forward(1)
position_2 = turtle_2.position()
if int(position_2[0]) == int(position_1[0]) and int(position_2[1]) == int(position_1[1]):
break
seed()
screen = Screen()
screen.setup(WIDTH * 1.25, HEIGHT * 1.25)
vertices = []
for _ in range(3):
x = randint(-WIDTH//2, WIDTH//2)
y = randint(-HEIGHT//2, HEIGHT//2)
vertices.append((x, y))
A, B, C = vertices
turtle_AtoB = Turtle(shape='turtle')
turtle_AtoB.penup()
turtle_AtoB.goto(A)
turtle_AtoB.pendown()
turtle_BtoA = Turtle(shape='turtle')
turtle_BtoA.penup()
turtle_BtoA.goto(B)
turtle_BtoA.pendown()
meet_in_the_middle(turtle_AtoB, turtle_BtoA)
turtle_BtoA.hideturtle()
turtle_AtoB.setheading(turtle_AtoB.towards(C))
turtle_AtoB.goto(C)
turtle_AtoB.hideturtle()
turtle_BtoC = Turtle(shape='turtle')
turtle_BtoC.penup()
turtle_BtoC.goto(B)
turtle_BtoC.pendown()
turtle_CtoB = Turtle(shape='turtle')
turtle_CtoB.penup()
turtle_CtoB.goto(C)
turtle_CtoB.pendown()
meet_in_the_middle(turtle_BtoC, turtle_CtoB)
turtle_CtoB.hideturtle()
turtle_BtoC.setheading(turtle_BtoC.towards(A))
turtle_BtoC.goto(A)
turtle_BtoC.hideturtle()
turtle_CtoA = Turtle(shape='turtle')
turtle_CtoA.penup()
turtle_CtoA.goto(C)
turtle_CtoA.pendown()
turtle_AtoC = Turtle(shape='turtle')
turtle_AtoC.penup()
turtle_AtoC.goto(A)
turtle_AtoC.pendown()
meet_in_the_middle(turtle_CtoA, turtle_AtoC)
turtle_AtoC.hideturtle()
turtle_CtoA.setheading(turtle_CtoA.towards(B))
turtle_CtoA.goto(B)
turtle_CtoA.hideturtle()
screen.exitonclick()
Turtles at work:
Finished drawing:
thanks to cdlane, I took his code and put some functionality into functions to make it a Little clearer (at least for me)
# -*- coding: cp1252 -*-
import turtle
from turtle import Turtle, Screen
from random import seed, randint
WIDTH, HEIGHT = 640, 480
def create_screen(width, height):
screen = Screen()
screen.setup(width * 1.25, height * 1.25)
return screen
def create_points(count,width = WIDTH, height = HEIGHT):
vertices = []
for _ in range(count):
x = randint(-width//2, width//2)
y = randint(-height//2, height//2)
vertices.append((x, y))
return vertices
def create_turtle_at_position(position):
turtle = Turtle(shape='turtle')
turtle.hideturtle()
turtle.penup()
turtle.goto(position)
turtle.showturtle()
turtle.pendown()
return turtle
def meet_in_the_middle(turtle_1, turtle_2):
position_2 = turtle_2.position()
while True:
turtle_1.setheading(turtle_1.towards(turtle_2))
turtle_1.forward(1)
position_1 = turtle_1.position()
if int(position_1[0]) == int(position_2[0]) and int(position_1[1]) == int(position_2[1]):
break
turtle_2.setheading(turtle_2.towards(turtle_1))
turtle_2.forward(1)
position_2 = turtle_2.position()
if int(position_2[0]) == int(position_1[0]) and int(position_2[1]) == int(position_1[1]):
break
turtle_1.hideturtle()
turtle_2.hideturtle()
return create_turtle_at_position(position_2)
def draw_median(P1st, P2nd, POpposite):
turtle_AtoB = create_turtle_at_position(P1st)
turtle_BtoA = create_turtle_at_position(P2nd)
turtle_AandBmiddle = meet_in_the_middle(turtle_AtoB, turtle_BtoA)
turtle_AandBmiddle.setheading(turtle_AandBmiddle.towards(POpposite))
turtle_AandBmiddle.goto(POpposite)
return turtle_AandBmiddle
seed()
sc = create_screen(WIDTH, HEIGHT)
for _ in range(5):
sc = create_screen(WIDTH, HEIGHT)
A, B, C = create_points(3)
draw_median(A,B,C)
draw_median(B,C,A)
draw_median(C,A,B)
sc.exitonclick()
mathematical it is the easiest way to calculate this by vector. Let me say you have a triangle ABC and want to draw a line from A to the middle of BC so your vector starts at A and ends on A + AB + 1/2 BC or A + AC + 1/2 CB (vectorial)
(ax) + (bx - ax) + 0.5 (cx - bx)
(ay) (by - ay) (cy - by)
that results in the coordinates for the opposite Point of
x = 0.5(cx + bx)
y = 0.5(cy + by)

Python Pattern Design

I'm trying to achieve the pattern below.
Got as far as doing the first line, then I have no clue how to code the rest of the pattern.
Here's what I've done so far:
#Timothy Shek
from graphics import*
#open Graph Window
def main():
win = GraphWin("Example",100,100)
x = 7
y = 7
radius = 5
while x<=30 :
centre = Point(x,y)
circle1 = Circle(centre,radius)
circle1.setFill("red")
circle1.draw(win)
x = x+10
while x>=35 and x<=65 :
centre = Point(x+5,y)
circle2 = Circle(centre,radius)
circle2.setFill("red")
circle2.draw(win)
x = x+10
print(x)
while x>=67:
centre = Point(x+10,y)
circle1 = Circle(centre,radius)
circle1.setFill("red")
circle1.draw(win)
x = x+10
main()
I got it guys, thanks
Heres the solution
#Timothy Shek
from graphics import*
#open Graph Window
def main():
win = GraphWin("Patch2" ,100,100)
for x in (5, 15, 25, 40,50,60,75,85,95):
for y in (5, 15, 25, 40,50,60,75,85,95):
c = Circle(Point(x+2,y), 5)
d = Circle(Point(x+2,y), 5)
c.draw(win)
d.draw(win)
c.setFill("Red")
d.setFill("Red")
if x==15 or x==50 or x== 85:
if y==15 or y==50 or y== 85:
c2 = Circle(Point(x+2,y),5)
c2.draw(win)
c2.setFill("White")
main()
While there is nothing wrong with your solution, this is a bit more performant
from graphics import *
def main():
win = GraphWin("Patch2" ,100,100)
coords = [5, 15, 25, 40, 50, 60, 75, 85, 95]
centers = set([coords[i] for i in range(1, len(coords), 3)])
for i in xrange(len(coords)):
for j in xrange(i+1):
x, y = (coords[i], coords[j])
c1 = Circle(Point(x+2,y), 5)
c2 = Circle(Point(y+2,x), 5)
c1.draw(win)
c2.draw(win)
if x in centers and y in centers:
c1.setFill("White")
c2.setFill("White")
else:
c1.setFill("Red")
c2.setFill("Red")
main()
Update: "Better" version
And since I got bored and I liked this problem (yes, I program when I'm bored) I made a fully parameter-ized version which you can do some fun stuff with, like.
Probably over your head :) But maybe you learn something from it, so I'm posting it.
from graphics import *
def drawPattern(scale):
# Inner method: Draw a square of circles given the top-left point
def drawSquare(win, xCoord, yCoord, squareSize=30, numCircles=3, scale=1, scaleCircles=False, outer_color="Red", inner_color="White"):
# Overwrite the default scaling
if scale > 1:
squareSize *= scale
if scaleCircles:
numCircles *= scale
radius = squareSize/(numCircles*2) # Divide by 2 since it's the radius
from math import sqrt, floor
centerDiff = (2*radius) * floor(sqrt(numCircles)) # Used for drawing off-color circles
# xrange uses an exclusive stop value, so go one value past to make inclusive
for x in xrange(radius, squareSize+radius, radius*2):
for y in xrange(squareSize-radius, x-radius, -radius*2):
c1 = Circle(Point(x+xCoord+2,y+yCoord), radius)
c2 = Circle(Point(y+yCoord+2,x+xCoord), radius)
c1.draw(win)
c2.draw(win)
if (centerDiff < x < squareSize - centerDiff) and (centerDiff < y < squareSize - centerDiff):
c1.setFill(inner_color)
c2.setFill(inner_color)
else:
c1.setFill(outer_color)
c2.setFill(outer_color)
win = GraphWin("Patch2 (x{})".format(scale), 100*scale,100*scale)
coords = [0, 35, 70]
for x in coords:
for y in coords:
drawSquare(win, x*scale, y*scale, scale=scale) # normal (boring) version
# drawSquare(win, x*scale, y*scale, scale=scale, scaleCircles=True, outer_color="Blue") # Picture version
def main():
drawPattern(3)
main()

How to properly create function that moves a shape using Zelle's 'graphics.py' program?

Question 17 of Ch. 6 in Zelle's 'Programming Python' books asks for a function that takes two arguments: 'shape', and 'newCenter', which will then move, or re-draw, an existing object based on the new points provided by a mouse-click.
I've been able to figure out how to do it if I add two more parameters to the function, "myX", and "myY", so I can then subtract the difference for the move method. What is eluding me is how to perform the same calculations using just the two parameters specified above. Here is my code:
def moveTo(shape, newCenter, myX, myY):
myShape = shape
myNewX = newCenter.getX()
myNewY = newCenter.getY()
myXUpd = myNewX - myX
myYUpd = myNewY - myY
myShape.move(myXUpd, myYUpd)
return myNewX, myNewY
def main():
win = GraphWin("My Graph Win", 500, 500)
win.setBackground("white")
win.setCoords(0, 0, 10, 10)
Text(Point(5, 8.5), "Please click 10 times.").draw(win)
myPoint = win.getMouse()
myX = myPoint.getX()
myY = myPoint.getY()
myCircle = Circle(myPoint, 2)
myCircle.draw(win)
for x in range(1, 10):
myNewPoint = win.getMouse()
myX, myY = moveTo(myCircle, myNewPoint, myX, myY)
win.close()
Also, any general tips for streamlining, style, or structure are also appreciated as I'm a rather new Python developer.
Thanks!
I figured this out on my own, so anyone going through the Zelle "Python Programming" book can learn from my experience. I just pulled the X and Y out of the shape object I was passing in, thus saving myself having to pass them in again separately. Here is the updated code with some of the fat trimmed down.
def moveTo(shape, newCenter):
oldCenter = shape.getCenter()
myOldX, myOldY = oldCenter.getX(), oldCenter.getY()
myNewX, myNewY = newCenter.getX(), newCenter.getY()
moveX = myNewX - myOldX
moveY = myNewY - myOldY
shape.move(moveX, moveY)
return shape
def main():
win = GraphWin("My Graph Win", 500, 500)
win.setBackground("white")
win.setCoords(0, 0, 10, 10)
Text(Point(5, 8.5), "Please click 10 times.").draw(win)
myPoint = win.getMouse()
myX, myY = myPoint.getX(), myPoint.getY()
myShape = Circle(myPoint, 2)
myShape.draw(win)
for x in range(1, 10):
newCenter = win.getMouse()
myShape = moveTo(myShape, newCenter)
win.close()

Categories

Resources