Infinite Loop Issue - Intersections - python

I tried out a system that hopefully will prevent the line from crossing over itself. However, when ran it created what appears to be an infinite loop. I am not sure what the issue is. Here is the code.
#detecting the overlap
intersection1 = Line1.intersection(Line1)
while Line1 == intersection1:
importlib.reload(tkinter)
print('failed attempt')
continue
while Line1 != intersection1:
print('successful attempt')
break
In order to run the program, the full code is needed which I will list below, but above is the section in question.
#imports
import tkinter
from tkinter import *
import random
from random import randint
import math
import time
import pip
import shapely
from shapely.geometry import LineString
import importlib
#setting up the canvas
master = Tk()
master.geometry("500x500")
master.title("Sprouts")
w = Canvas(master, width=500, height=500, bg="white")
w.pack()
#creating the circle
def create_circle(x, y, r, w): #center coordinates, radius
x0 = x - r
y0 = y - r
x1 = x + r
y1 = y + r
return w.create_oval(x0, y0, x1, y1)
#creating coordinate variables
xC = random.randint(10,490)
yC = random.randint(10,490)
xC2 = random.randint(10,490)
yC2 = random.randint(10,490)
L1C1 = random.randint(10,490)
L1C2 = random.randint(10,490)
L1C3 = random.randint(10,490)
L1C4 = random.randint(10,490)
#displaying the circle
c1 = create_circle(xC, yC, 5, w)
c2 = create_circle(xC2, yC2, 5, w)
#displaying the line #implementing the curve
Line1 = LineString([(xC, yC), (xC2, yC2)]
or [(xC, yC), (L1C1, L1C2), (xC2, yC2)]
or [(xC,yC), (L1C1, L1C2), (L1C3, L1C4), (xC2, yC2)])
Line1show = w.create_line(xC, yC, xC2, yC2 or
xC, yC, L1C1, L1C2, xC2, yC2 or
xC, yC, L1C1, L1C2, L1C3, L1C4, xC2, yC2,
smooth='1',width="2")
#detecting the overlap
intersection1 = Line1.intersection(Line1)
while Line1 == intersection1:
importlib.reload(tkinter)
print('failed attempt')
continue
while Line1 != intersection1:
print('sucessful attempt')
break
w.mainloop()

the problem is the use of continue which return you all the way back to the beginning of your loop
here is a simple illustrative example that do the same as your problematic code section
>>> msj=""
>>> while msj!="yes":
print("msj is not 'yes'")
continue
msj=input("write msj")
msj is not 'yes'
msj is not 'yes'
msj is not 'yes'
...
here you would never get to the msj=input("write msj") because the continue return to the beginning of the loop and the previous part make no change to the condition of the loop hence you end in an infinite loop...
A more correct use of continue is with conditionals if statements in order to skip doing stuff with something you don't need to work on like for example in pseudocode something like this:
while dowork:
if not condition(data):
continue
result=work_on_data(data)
if check_if_done(result):
break
data=get_next_data()

Related

Error object has no attribute in Paint app

This is the code, I got it from here https://www.youtube.com/watch?v=uW-NLL9dlBs
After many attempts, I solved some issues, but I still couldnt get it to work.
Its supposed to be an app for painting. I wanted it to have very large pixels with invisible grid too, so painting in it would create low resolution pixel art, similar to this. I dont know how to do that, as I couldnt find it anywhere. pixel image
from tkinter import *
from tkinter.ttk import Scale
from tkinter import colorchooser,filedialog,messagebox
import PIL.ImageGrab as ImageGrab
class Paint():
def __init__(self,root):
self.root = root
self.root.title("Paint")
self.root.geometry("800x520")
self.root.configure(background='white')
self.root.resizable(0,0)
self.pen_color = "black"
self.eraser_color = "white"
self.color_frame = LabelFrame(self.root,text='Color',font = ('arial',15),bd=5,relief=RIDGE,bg='white')
self.color_frame.place(x=0,y=0,width=70,height=185)
colors = ['#ff0000','#ff4dd2','#ffff33','#000000','#0066ff','#660033','#4dff4d','#b300b3','#00ffff','#808080','#99ffcc','#336600','#ff9966','#ff99ff','#00cc99']
i=j=0
for color in colors:
Button(self.color_frame,bg=color,bd=2,relief=RIDGE,width=3,command=lambda col =color:self.select_color(col)).grid(row=i,column=j)
i+=1
if i==6:
i=0
j=1
self.eraser_button = Button(self.root,text="ERASER",bd=4,bg='white',command=self.eraser,width=8,relief=RIDGE)
self.eraser_button.place(x=0,y=187)
self.clear_button = Button(self.root, text="Clear",bd=4,bg='white',command=lambda : self.canvas.delete("all"),width=8,relief=RIDGE)
self.clear_button.place(x=0,y=217)
self.save_button = Button(self.root,text="Save",bd=4,bg='white',command=self.save_paint,width=8,relief=RIDGE)
self.save_button.place(x=0,y=247)
self.canvas_color_button = Button(self.root,text="Canvas", bd=4 , bg='white', command=self.canvas_color(),width=8,relief=RIDGE)
self.canvas_color_button.place(x=0, y=277)
self.pen_size_scale_frame = LabelFrame(self.root,text="size",bd=5,bg='white',font=('arial',15,'bold'),relief=RIDGE)
self.pen_size_scale_frame.place(x=0,y=310,height=200,width=70)
self.pen_size = Scale(self.pen_size_scale_frame,orient=VERTICAL,from_ = 50, to = 0,length=170)
self.pen_size.set(1)
self.pen_size.grid(row=0,column=1,padx=15)
self.canvas = Canvas(self.root,bg='white',bd=5,relief=GROOVE,height=500,width=700)
self.canvas.place(x=80,y=0)
self.canvas.bind("<B1-Motion>",self.paint)
def paint(self,event):
x1,y1 = (event.x-2),(event.y-2)
x2,y2 = (event.x + 2),(event.y + 2)
self.canvas.create_oval(x1,y1,x2,y2,fill=self.pen_color,outline=self.pen_color,width=self.pen_size.get())
def select_color(self,col):
self.pen_color = self.eraser_color
def eraser(self):
self.pen_color = "white"
def canvas_color(self):
color = colorchooser.askcolor()
self.canvas.configure(background=color[1])
self.eraser_color = color[1]
def save_paint(self):
try:
filename = asksaveasfilename(defaultextension='.jpg')
x = self.root.winfo_rooty() + self.canvas.winfo_x()
y = self.root.winfo_rooty() + self.canvas.winfo_y()
x1 = x + self.canvas.winfo_width()
y1 = y + self.canvas.winfo_height()
ImageGrab.grab().crop((x,y,x1,y1)).save(filename)
messagebox.showinfo('paint says','image is saved as ' + str(filename))
except:
messagebox.showerror("paint says","unable to save image ,\n something went wrong")
if __name__ == "__main__":
root = Tk()
p = Paint(root)
root.mainloop()
In order to get your paint program working, the following bugs need to be addressed.
The self.canvas_color_button command has a bug. Just remove the parens to make it work.
There's a problem with color selection methods.
Here is the solution.
def select_color(self,col):
self.pen_color = col
def eraser(self):
self.pen_color = self.eraser_color
When saving a drawing, the image is not cropped correctly due to other widgets.
self.color_frame has a width of 70.
Your canvas is defined with a borderwidth(5) and a highlightthickness(2).
These values must be taken into account.
Here is one solution to crop your saved images correctly.
xoffset = self.color_frame.winfo_width()
yoffset = int(self.canvas["borderwidth"]) + int(self.canvas["highlightthickness"])
x = self.root.winfo_rooty() + self.canvas.winfo_x()
y = self.root.winfo_rooty() + self.canvas.winfo_y() + yoffset
x1 = x + self.canvas.winfo_width() - xoffset
y1 = y + self.canvas.winfo_height() - (yoffset * 2)

tKinter switch color on hotkey click

I have a program that opens a window and a circle at the center that is filled green at the start. I want this circle to change from red to green and green to red each time I press a button (r in this code) however I can only change the color once
from tkinter import *
import keyboard
if __name__ == '__main__':
window = Tk()
window.title("On Record")
window.configure(width=500, height=300)
window.configure(bg='lightgray')
myCanvas = Canvas(window)
myCanvas.pack()
def daire(x, y, r, canvasName, color): # center coordinates, radius
x0 = x - r
y0 = y - r
x1 = x + r
y1 = y + r
return canvasName.create_oval(x0, y0, x1, y1, fill=color)
# move window center
winWidth = window.winfo_reqwidth()
winwHeight = window.winfo_reqheight()
posRight = int(window.winfo_screenwidth() / 2 - winWidth / 2)
posDown = int(window.winfo_screenheight() / 2 - winwHeight / 2)
window.geometry("+{}+{}".format(posRight, posDown))
color = "green"
def onKeyPress(event):
print("pressed")
counter = 0
counter = counter + 1
print(counter)
if counter % 2 == 0:
color = "green"
else:
color = "red"
daire(190, 135, 120, myCanvas, color)
window.bind("r", onKeyPress)
daire(190, 135, 120, myCanvas, "green")
window.mainloop()
The problem was the event function is reliant on counter being odd or even, but it auto resets it to 0 every time is is run. One solution to this is to place the counter outside of the function and call it as a global.
from tkinter import *
import keyboard
if __name__ == '__main__':
window = Tk()
window.title("On Record")
window.configure(width=500, height=300)
window.configure(bg='lightgray')
myCanvas = Canvas(window)
myCanvas.pack()
def daire(x, y, r, canvasName, color): # center coordinates, radius
x0 = x - r
y0 = y - r
x1 = x + r
y1 = y + r
return canvasName.create_oval(x0, y0, x1, y1, fill=color)
# move window center
winWidth = window.winfo_reqwidth()
winwHeight = window.winfo_reqheight()
posRight = int(window.winfo_screenwidth() / 2 - winWidth / 2)
posDown = int(window.winfo_screenheight() / 2 - winwHeight / 2)
window.geometry("+{}+{}".format(posRight, posDown))
color = "green"
counter = 0
def onKeyPress(event):
global counter
print("pressed")
counter += 1
print(counter)
if counter % 2 == 0:
color = "green"
else:
color = "red"
daire(190, 135, 120, myCanvas, color)
window.bind("r", onKeyPress)
daire(190, 135, 120, myCanvas, color)
window.mainloop()
Out of interest do you actually need to be able to track how many times r is pressed? Its implied by your script but not explicitly stated. Otherwise theres more streamlined ways of doing this by referring directly to tkinter elements, as is often done with button toggles as displayed in this post.

how do you prevent a line from intersecting itself

I have been working on a code that randomly generates a line from one random point to another. However, I would like to have the line created not intersect itself. Is there a way to have the line replaced if it intersects itself, or to possibly refresh the random coordinates? If someone could help that would be great! Here is the code I have created (and yes as far as i know, all of it is necessary in order for it to run at all);
#imports
from tkinter import *
import random
from random import randint
import math
import pip
import shapely
from shapely.geometry import LineString
#setting up the canvas
master = Tk()
master.geometry("500x500")
master.title("Sprouts")
w = Canvas(master, width=500, height=500, bg="white")
w.pack()
#creating the circle
def create_circle(x, y, r, w): #center coordinates, radius
x0 = x - r
y0 = y - r
x1 = x + r
y1 = y + r
return w.create_oval(x0, y0, x1, y1)
#creating coordinate variables
xC = random.randint(10,490)
yC = random.randint(10,490)
xC2 = random.randint(10,490)
yC2 = random.randint(10,490)
L1C1 = random.randint(10,490)
L1C2 = random.randint(10,490)
L1C3 = random.randint(10,490)
L1C4 = random.randint(10,490)
#displaying the circle
c1 = create_circle(xC, yC, 5, w)
c2 = create_circle(xC2, yC2, 5, w)
#displaying the line #implementing the curve
Line1 = LineString([(xC, yC), (xC2, yC2)]
or [(xC, yC), (L1C1, L1C2), (xC2, yC2)]
or [(xC,yC), (L1C1, L1C2), (L1C3, L1C4), (xC2, yC2)])
Line1show = w.create_line(xC, yC, xC2, yC2 or
xC, yC, L1C1, L1C2, xC2, yC2 or
xC, yC, L1C1, L1C2, L1C3, L1C4, xC2, yC2,
smooth='1',width="2")
#defining the intersects variable
intersection1 = Line1.intersection(Line1)
if Line1 == intersection1:
print('try again') #this is a filler so the code functions
#either replace Line1, or use another method to prevent intersection
w.mainloop()

How do I correctly implement a bubble sort algorithm in python tkinter?

I am making a series of articles about sorting algorithms, and the first part is about bubble sorting, I have the GUI elements in place, but the sorting algorithm itself is not working correctly. it randomly swaps a series of lines of different lengths, but the sorting doesn't work as expected. It is written in python Tkinter, I think the main problem comes from how I programmed the sorting like two lists, one on the screen and one on memory. It would be helpful if you could also explain my mistake to me.
import tkinter as tk
import random
def swap_two_pos(pos_0, pos_1):
"""This does the graphical swapping of the rectangles on the canvas
by moving one rectangle to the location of the other, and vice versa
"""
x_00, _, x_01, _ = canvas.coords(pos_0)
x_10, _, x_11, _ = canvas.coords(pos_1)
# moves each rectangle to the x position of the other; y remains unchanged
canvas.move(pos_0, x_10-x_00, 0)
canvas.move(pos_1, x_01-x_11, 0)
def sort_two(pos_0, pos_1):
x_00, y1, x_01, _ = canvas.coords(pos_0)
x_10, y2, x_11, _ = canvas.coords(pos_1)
# moves each rectangle to the x position of the other; y remains unchanged
if y2 > y1:
canvas.move(pos_0, x_10-x_00, 0)
canvas.move(pos_1, x_01-x_11, 0)
def rand_sort():
for i in range(50000):
rd1 = random.randint(0, 58)
rd2 = random.randint(0, 58)
pos_1 = barList[rd1]
pos_2 = barList[rd2]
sort_two(pos_1, pos_2)
barList[rd1], barList[rd2] = barList[rd2], barList[rd1]
def sort ():
n = len(barList)
# Traverse through all array elements
for i in range(n):
# Last i elements are already in place
for j in range(0, n-i-1):
sort_two(barList[j], barList[j+1])
barList[j], barList[j+1] = barList[j+1], barList[j]
else:
break
def random_swap():
"""Not a sort yet, but you have the bare bones operations
so the swap is executed
"""
for i in range(500):
rd1 = random.randint(0, 58)
rd2 = random.randint(0, 58)
pos_0 = barList[rd1]
pos_1 = barList[rd2]
swap_two_pos(pos_0, pos_1)
# it is necessary to swap the values in the list too
barList[rd1], barList[rd2] = barList[rd2], barList[rd1]
window = tk.Tk()
window.title('Sorting')
window.geometry('600x400')
# button to command the swap
tk.Button(window, text='swap', command=random_swap).pack()
tk.Button(window, text='sort', command=sort).pack()
xstart = 5
xend = 15
canvas = tk.Canvas(window, width='900', height='900')
canvas.pack()
barList = []
lengthList = []
Y = 5
for x in range(1,60):
bar = canvas.create_rectangle(xstart, Y, xend, 395, fill='red')
barList.append(bar)
xstart += 10
xend += 10
Y += 5
for bar in barList:
x = canvas.coords(bar)
length = x[3]-x[1]
lengthList.append(length)
window.mainloop()
The biggest problem is that inside sort_two you have if
if y2 > y1:
canvas.move(pos_0, x_10-x_00, 0)
canvas.move(pos_1, x_01-x_11, 0)
which replaces elements only if y2 > y1
but after sort_two() you use barList
sort_two(pos_1, pos_2)
barList[rd1], barList[rd2] = barList[rd2], barList[rd1]
which always replaces elements on list.
And this way you have wrong results on screen.
You could return True/False from sort_two() to control when to change elements on barList
if y2 > y1:
canvas.move(pos_0, x_10-x_00, 0)
canvas.move(pos_1, x_01-x_11, 0)
return True
else:
return False
and
if sort_two(pos_1, pos_2):
barList[rd1], barList[rd2] = barList[rd2], barList[rd1]
Here finall code
I use simple calculation for replacing elements on canvas
x1, _, _, _ = canvas.coords(pos_0)
x2, _, _, _ = canvas.coords(pos_1)
diff = x1 - x2
canvas.move(pos_0, -diff, 0)
canvas.move(pos_1, +diff, 0)
I also removed
else:
break
which stop animation after every replace and it needs to click button sort again and again - and I use
window.update()
time.sleep(0.1)
so it displays animation (slowly) to the end of sorting and I don't have to click button sort
import tkinter as tk
import random
import time
def swap_two_pos(pos_0, pos_1):
"""This does the graphical swapping of the rectangles on the canvas
by moving one rectangle to the location of the other, and vice versa
"""
x1, _, _, _ = canvas.coords(pos_0)
x2, _, _, _ = canvas.coords(pos_1)
diff = x1 - x2
canvas.move(pos_0, -diff, 0)
canvas.move(pos_1, +diff, 0)
def sort_two(pos_0, pos_1):
x1, y1, _, _ = canvas.coords(pos_0)
x2, y2, _, _ = canvas.coords(pos_1)
diff = x1 - x2
# moves each rectangle to the x position of the other; y remains unchanged
if y2 > y1:
canvas.move(pos_0, -diff, 0)
canvas.move(pos_1, +diff, 0)
return True
else:
return False
def rand_sort():
for i in range(50000):
rd1 = random.randint(0, 58)
rd2 = random.randint(0, 58)
pos_1 = barList[rd1]
pos_2 = barList[rd2]
if sort_two(pos_1, pos_2):
barList[rd1], barList[rd2] = barList[rd2], barList[rd1]
def sort ():
n = len(barList)
# Traverse through all array elements
for i in range(n):
# Last i elements are already in place
for j in range(0, n-i-1):
if sort_two(barList[j], barList[j+1]):
barList[j], barList[j+1] = barList[j+1], barList[j]
window.update()
time.sleep(0.1)
def random_swap():
"""Not a sort yet, but you have the bare bones operations
so the swap is executed
"""
for i in range(500):
rd1 = random.randint(0, 58)
rd2 = random.randint(0, 58)
pos_0 = barList[rd1]
pos_1 = barList[rd2]
swap_two_pos(pos_0, pos_1)
# it is necessary to swap the values in the list too
barList[rd1], barList[rd2] = barList[rd2], barList[rd1]
window = tk.Tk()
window.title('Sorting')
window.geometry('600x400')
# button to command the swap
tk.Button(window, text='swap', command=random_swap).pack()
tk.Button(window, text='sort', command=sort).pack()
xstart = 5
xend = 15
canvas = tk.Canvas(window, width='900', height='900')
canvas.pack()
barList = []
lengthList = []
Y = 5
for x in range(1,60):
bar = canvas.create_rectangle(xstart, Y, xend, 395, fill='red')
barList.append(bar)
xstart += 10
xend += 10
Y += 5
for bar in barList:
x = canvas.coords(bar)
length = x[3]-x[1]
lengthList.append(length)
window.mainloop()

How to display and update a score on screen?

My question is about displaying and updating text, in order to display the score on screen.
I would like to create a score like the real game that would appear on the screen. But after researching Google, I have not found anyone wishing to increase a score on the screen ...
Indeed, I would like the score to increase each time the bird passes between the pipes and therefore whenever the pipes have an X of 67 pixels. So does anyone know how to do this?
from tkinter import *
import random
from random import randint
def sauter(event):
canvas.move(image_oiseau, 0, -10*DY)
def deplacement():
global tuyx,tuyx2,h,H,oisx,oisy,solx,sol2x
x0, y0, x1, y1 = canvas.bbox(image_oiseau)
if y1 < 416:
canvas.move(image_oiseau, 0, DY)
canvas.coords(image_sol,solx,512)
if solx >= -144:
solx=solx-5
else:
solx=144
canvas.coords(image_sol2,sol2x,512)
if sol2x >= 144:
sol2x=sol2x-5
else:
sol2x=432
canvas.coords(image_tuyau_haut,tuyx,h)
canvas.coords(image_tuyau_bas,tuyx,h-241)
if tuyx>=-28:
tuyx=tuyx-5
else:
tuyx=316
h=randint(256,505)
canvas.coords(image_tuyau_haut2,tuyx2,H)
canvas.coords(image_tuyau_bas2,tuyx2,H-241)
if tuyx2>=-28:
tuyx2=tuyx2-5
else:
tuyx2=316
H=randint(256,505)
canvas.after(40,deplacement)
LARGEUR = 286
HAUTEUR = 510
DY = 5
tuyx=316
tuyx2=488
h=randint(256,505)
H=randint(256,505)
oisx=67
oisy=244
solx=144
sol2x=432
fenetre = Tk()
canvas = Canvas(fenetre, width=LARGEUR, height=HAUTEUR)
fond = PhotoImage(file="background-day.png")
fond2 = PhotoImage(file="background-night.png")
fond=[fond,fond2]
F= random.choice(fond)
canvas.create_image(144,256, anchor=CENTER,image=F)
tuyau_haut = PhotoImage(file="tuyau_vers_le_haut.png")
image_tuyau_haut = canvas.create_image(tuyx,h,anchor=CENTER,image=tuyau_haut)
image_tuyau_haut2 = canvas.create_image(tuyx2,H,anchor=CENTER,image=tuyau_haut)
tuyau_bas = PhotoImage(file="tuyau_vers_le_bas.png")
image_tuyau_bas = canvas.create_image(tuyx,h,anchor=CENTER,image=tuyau_bas)
image_tuyau_bas2 = canvas.create_image(tuyx2,H,anchor=CENTER,image=tuyau_bas)
sol = PhotoImage(file="sol-day.png")
image_sol = canvas.create_image(144,512, anchor=S,image=sol)
image_sol2 = canvas.create_image(432,512, anchor=S,image=sol)
oiseau = PhotoImage(file="yellowbird-midflap.png")
oiseau2 = PhotoImage(file="bluebird-midflap.png")
oiseau3 = PhotoImage(file="redbird-midflap.png")
oiseau=[oiseau,oiseau2,oiseau3]
O=random.choice(oiseau)
image_oiseau=canvas.create_image(oisx,oisy, anchor=W,image=O)
deplacement()
canvas.pack()
canvas.focus_set()
canvas.bind("<space>",sauter)
fenetre.mainloop()
Could someone explain the problem to me because I thought it would be easy :(
Here are the pictures of the game :)
Here are the pictures of the game
Here is one approach to display the scores: It uses a tk.Label, that is updated at the same time the score increases.
The trigger that increases the score is currently a random call to on_change; you can modify this to be a test if a pipe x coordinates becomes lower than the bird x coordinates (the bird successfully crossed the obstacle)
You can, if you want relocate the score label on the canvas.
import random
import tkinter as tk
WIDTH, HEIGHT = 500, 500
def create_pipes():
pipes = []
for x in range(0, WIDTH, 40):
y1 = random.randrange(50, HEIGHT - 50)
y0 = y1 + 50
pipes.append(canvas.create_line(x, 0, x, y1))
pipes.append(canvas.create_line(x, y0, x, HEIGHT))
return pipes
def move_pipes():
for pipe in pipes:
canvas.move(pipe, -2, 0)
x, y0, _, y1 = canvas.coords(pipe)
if x < 0:
canvas.coords(pipe, WIDTH+20, y0, WIDTH+20, y1)
if random.randrange(0, 20) == 10:
on_change()
root.after(40, move_pipes)
def on_change():
global score
score += 1
score_variable.set(f'score: {score}')
root = tk.Tk()
tk.Button(root, text='start', command=move_pipes).pack()
score = 0
score_variable = tk.StringVar(root, f'score: {score}')
score_lbl = tk.Label(root, textvariable=score_variable)
score_lbl.pack()
canvas = tk.Canvas(root, width=WIDTH, height=HEIGHT, bg="cyan")
canvas.pack()
pipes = create_pipes()
root.mainloop()

Categories