1

I'm trying to create a pathfinding representation (using Dijkstra). the way my graphics work is as followed:

    def run_visuals(self):
    """
    runs the visuals in a loop
    """
    run = True
    self.draw_grid()
    while run:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False

            elif event.type == pygame.MOUSEBUTTONDOWN:  # mouse click
                x, y = event.pos
                row = x // BLOCK_SIZE
                col = y // BLOCK_SIZE
                if event.button == RIGHT_MOUSE_CLICK:  # right click - source and dest
                    if not self.is_src_button_init:
                        init_src_node()
                    elif not self.is_dest_button_init:
                        init_dest_node()
                elif event.button == LEFT_MOUSE_CLICK:  # left click - bad nodes
                    self.add_bad_nodes_with_mouse(x, y)
                    self.draw_nodes("bad")
                    self.graph.remove_edges_of_bad_nodes(self.bad_nodes)

            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_RETURN:  # pressed enter - run algorithm
                    dijkstra(self.graph, self.source_node, self.window, self.dest_node)
        pygame.display.update()
        self.clock.tick(FPS)

notice when ENTER key is clicked, this is where I call the algorithm:

source.set_dist_from_source(0)
Q = build_min_heap(graph)  # O(V)
while Q:  # O(V)
    u = heapq.heappop(Q)  # pops the min val based on dist from source (get value and remove from heap) O(logV)
    if u == dest:
        break
    neighbors_of_u = graph.get_neighbors()[u.name]
    for v in neighbors_of_u:  # O(E)
        # drawing neighbors:
        if not v.is_colored:
            block = get_block_from_node(v)
            block.draw(window, VISITED_COLOR)
        # checking min path:
        weight_u_v = graph.get_edge_weight(u.name, v.name)
        v_dist = v.dist_from_source
        u_dist = u.dist_from_source
        if v_dist > u_dist + weight_u_v:
            v.set_dist_from_source(u_dist + weight_u_v)
            v.set_prev(u) # updating prev is done to reconstruct the path itself
            heapq.heappush(Q, v)  # O(logV)
print_path(window, source, dest)

notice the lines

block = get_block_from_node(v)
block.draw(window, VISITED_COLOR)

this is the part I wish to display, but with a delay. this code currently works, but the blocks are colored so fast that the user can't see the process of the painting. I've tried adding a clock.tick(10) under the line block.draw(window, VISITED_COLOR), where clock=pygame.time.Clock(), but this seems to make everything just stop (crashed the window)

this obviously isn't the entire code, but I believe that it is all the relevant code, would appreciate any help!

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
Hadar
  • 658
  • 4
  • 17

1 Answers1

1

If you want to show the changes after every single block, then you have to update the display and handle the events after every single block. See the documentation of pygame.event.pump():

For each frame of your game, you will need to make some sort of call to the event queue. This ensures your program can internally interact with the rest of the operating system.

Additionally you can control the fames per second by pygame.time.Clock.tick For instance:

clock=pygame.time.Clock()
while Q:  # O(V)
    # [...]

    for v in neighbors_of_u:  # O(E)
        # [...]

        # drawing neighbors:
        if not v.is_colored:
            block = get_block_from_node(v)
            block.draw(window, VISITED_COLOR)

            display.flip()
            pygame.event.pump()
            clock.tick(10)

        # [...]
Rabbid76
  • 202,892
  • 27
  • 131
  • 174