The most common way to solve this problem is to check if the circumferences overlap. To see if two circles overlap, you only need to know their radius and center (which is what you use to create them). Bearing this, it is enough to calculate the distance between both, which is not more than the calculation of the hypotenuse of a right triangle (Pythagorean Theorem):
With what the formula to calculate the distance is:
Taking the above into account, it suffices to create a function in Python that returns if two circumferences overlap or not and for each new circumference created randomly we check if it overlaps with any of the esxistentes. To do this we keep each circumference in a set ( set
) as a tuple of the form (x, y, radio)
and we use any
to do the check for each new circle to create. We can also add a third condition so that the new circles not only do not overlap, but are at a certain minimum distance from the rest:
def solapamiento(cir1, cir2, esp = 0):
# cir1 y cir2 son tuplas de la forma (x, y, radio)
# esp es la separación mínima que ha de haber entre circunferencias
distancia = ((cir2[0] - cir1[0])**2 + (cir2[1] - cir1[1])**2)**0.5
return (cir1[2] + cir2[2] + esp) > abs(distancia)
circulos = set()
espaciamiento = 10
n = 10
while len(circulos) < n:
x= random.randint (10,1000)
y = random.randint (20,700)
r = 20
cir = (x, y, r)
if not any(solapamiento(cir, c, espaciamiento) for c in circulos):
circulos.add(cir)
Logically, you have to be careful with the parameters. A greater radius or greater separation less circles can be created and more difficult is that random
of with an accepted circle. You can adapt the while
so that if you do not find all the circles in i
iterations, leave and draw the ones you have, avoiding that if we ask you to create more circles than possible for the available space, you can iterate infinitely .
Your code would look like this:
import random
import tkinter as tk
class MyCanvas(tk.Canvas):
def __init__(self, parent, *args, **kwargs):
tk.Canvas.__init__(self, parent, *args, **kwargs)
def create_circle (self, x, y, r, **kwargs):
return self.create_oval (x-r, y-r, x+r, y+r, **kwargs)
colores=["red", "blue", "yellow", "purple", "green", "black",
"white", "#5E00FF"]
ventana = tk.Tk ()
ventana.title ("Ventana")
label1 = tk.Label (ventana,text=" Jugador 1 ")
label1.grid()
label1 = tk.Label (ventana,text ="Puntuacion: ")
label1.grid()
canvas = MyCanvas(ventana, width=1500, height=900, borderwidth=0,
highlightthickness=0, bg= "orange")
canvas.grid()
def solapamiento(cir1, cir2, esp = 0):
# cir1 y cir2 son tuplas de la forma (x, y, radio)
# esp es la separación mínima que ha de haber entre circunsferencias
distancia = ((cir2[0] - cir1[0])**2 + (cir2[1] - cir1[1])**2)**0.5
return (cir1[2] + cir2[2] + esp) > abs(distancia)
circulos = set()
espaciamiento = 10
n = 10
while len(circulos) < n:
x= random.randint(10,1000)
y = random.randint(20,700)
r = random.randint(15,40)
color = random.choice(colores)
cir = (x, y, r)
if not any(solapamiento(cir, c, espaciamiento) for c in circulos):
circulos.add(cir)
canvas.create_circle (x, y, r, fill = color)
ventana.mainloop ()
I have modified some things, in addition to the above:
-
You should not use the way to import from módulo import *
in Python. It is a bad practice, dangerous in complex and extensive codes, very inefficient with memory and makes reading by third parties difficult. Remember the zen of Python: "Explicit better than implicit". The common way is to use import tkinter as tk
, you can also use import tkinter
or from tkinter import Canvas, Label, ...
.
-
The way you create your create_circle
method is a bit confusing and not very appropriate. It is better and safer to create a class that inherits Canvas
instead. In this case MyCanvas
(call it what you want) has your method create_circle
but the class tkinter.Canvas
is left intact. Modifying the latter directly can have unexpected consequences, for example if another widget uses the original class.
-
Finally, in the previous code the radius and the color are also random. You can eliminate the behavior by changing the variables by radio = 20
and color = colores[0]
, for example.
An example of how it is: