python-3.xgraphics2dzelle-graphics

Updating points one by one to a window using Zelle graphics.py


I have written some codes to draw randomly located points, as many as I wanted to, and make them spread like fluid for a while. Also I wanted them not to get into each other. There is no problem running it, but in some cases it takes really long time to finish a point's spreading, so I realized that's not that efficient.

I would be happy to get some help to make it more efficient.

This is what I meant by "like fluid"

from graphics import *
import time, random

racepoints = {} # {0:[(),()],1:[(),()]}
allpoints = []
races = {}
tx, ty = int(input("x=")), int(input("y="))

def Window():
    global win, sure, spreadSize
    win = GraphWin("Pencere", tx, ty)
    starttime = time.time()
    Start()
    spreadSize = int(input("Başlangıç boyutu?"))
    Spread(spreadSize)
    finishtime = time.time()
    sure = (finishtime - starttime)
    writeTime()
    print("Bitti! Ve {} saniye sürdü!".format(sure))
    time.sleep(5)


def writeTime():
    timefile = open("C:\\Python36\\timefile.py", "r")
    gotta_rewrite = timefile.readlines()
    timefile.close()
    timefile = open("C:\\Python36\\timefile.py", "w")
    gotta_rewrite.append("\n{} ırk, {} genişlik, {}*{} alan, {} saniye sürdü.".format(racecount, spreadSize, tx, ty, sure))
    timefile.seek(0)
    timefile.writelines(gotta_rewrite)
    timefile.close()


def Start():
    global racecount
    racecount = int(input("Kaç tane ırk olsun?"))
    for i in range(racecount):
        randomcolor = color_rgb(random.randrange(255), random.randrange(255), random.randrange(255))
        races[i] = randomcolor
        racepoints[i] = []
        nx = random.randrange(tx)
        ny = random.randrange(ty)
        randomstartpoint = Point(nx, ny)
        randomstartpoint.setFill(races[i])
        randomstartpoint.draw(win)
        allpoints.append((nx, ny))
        (racepoints[i]).append((nx, ny))


def Spread(maxsize):
    defaultsize = maxsize
    for i in range(racecount):
        maxsize = defaultsize
        while maxsize > 0:
            for point in list(racepoints[i]):
                lx, ly = point
                ax, ay = 0, 0
                while ax == 0 and ay == 0:
                    ax = random.choice([-1, 0, 1])
                    ay = random.choice([-1, 0, 1])
                if (lx + ax, ly + ay) not in allpoints:
                    lx += ax
                    ly += ay
                    newpoint = Point(lx, ly)
                    newpoint.setFill(races[i])
                    newpoint.draw(win)
                    (racepoints[i]).append((lx, ly))
                    allpoints.append((lx, ly))
                else:
                    pass
            maxsize -= 1


Window()

Solution

  • I've taken a different approach this time compared to my initial attempt in that this solution relies heavily on set logic to maintain the points. (The colors come off as a bit pastel due to my use of win.plot() instead of Point.draw() but that's a minor implementation detail)

    As before, I use the color as a dictionary key so my code makes sure the random color chosen is unique.

    import time
    from random import randrange
    from collections import defaultdict
    from graphics import *
    
    def Window():
        global tx, ty, win
    
        tx, ty = int(input("x = ")), int(input("y = "))
        race_count = int(input("How many races do you have? "))
        spread_size = int(input("Maximum spread? "))
    
        win = GraphWin("Window", tx, ty)
    
        start_time = time.time()
    
        Start(race_count)
        Spread(spread_size)
    
        finish_time = time.time()
        time_difference = finish_time - start_time
    
        print("Done! And it took {} seconds!".format(time_difference))
        writeTime(time_difference, spread_size, race_count)
        time.sleep(5)
    
    def writeTime(sure, spread_size, race_count):
        try:
            with open("timefile.py") as time_file:
                gotta_rewrite = time_file.readlines()
        except FileNotFoundError:
            gotta_rewrite = []
    
        gotta_rewrite.append("\n{} race, {} width, {} * {} space, {} seconds.".format(race_count, spread_size, tx, ty, sure))
    
        with open("timefile.py", "w") as time_file:
            time_file.writelines(gotta_rewrite)
    
    def Start(race_count):
        for _ in range(race_count):
            random_color = color_rgb(randrange(255), randrange(255), randrange(255))
    
            while random_color in races:
                random_color = color_rgb(randrange(255), randrange(255), randrange(255))
    
            nx, ny = randrange(tx), randrange(ty)
            win.plot(nx, ny, random_color)
    
            races[random_color].add((nx, ny))
    
    def Spread(spread_size):
        for _ in range(spread_size):
            for color, points in races.items():
                for point in list(points):  # need copy of points as it'll be modified in loop
    
                    candidates = set()
    
                    x, y = point
    
                    for dy in range(-1, 2):
                        for dx in range(-1, 2):
                            candidates.add((x + dx, y + dy))
    
                    candidates = candidates.difference(*races.values())
    
                    if candidates:
                        new_point = candidates.pop()
                        points.add(new_point)
    
                        nx, ny = new_point
    
                        if 0 < nx < tx and 0 < ny < ty:  # only draw visible points
                            win.plot(nx, ny, color)
    
    races = defaultdict(set)
    
    Window()
    

    Working the points round robin, rather than completing one and moving onto another, seems truer to the intent. You can compare your new solution on the left to mine on the right where they both have 50 races:

    enter image description here

    On mine on the right, you can nearly count all 50 races but on yours, you can only spot half that number due to losses from overlap.