1

I want to build some visualizations for searching algorithms (BFS, A* etc.) within a grid.

My solution should show each step of the algorithm using CodeSkulptor simplegui (or the offline version using SimpleGUICS2Pygame.)

I've made a version which highlights all the cells visited by changing their color, but I've run into trouble trying to make the path display step-by-step with a time delay between each step.

I've extracted the essence of the problem and created a minimal example representing it in the code below, also run-able online here: http://www.codeskulptor.org/#user47_jB2CYfNrH2_2.py

What I want is during the change_colors() function, for there to be a delay between each iteration. CodeSkulptor doesn't have time.sleep() available, and I don't think it would help anyway.

CodeSkulptor does have timers available, which might be one solution, although I can't see how to use one in this instance.

Code below:

import time

try:
    import simplegui
except ImportError:
    import SimpleGUICS2Pygame.simpleguics2pygame as simplegui

    simplegui.Frame._hide_status = True

TITLE = "TEST"
FRAME_WIDTH = 400
FRAME_HEIGHT = 400
DELAY = 10


class Square:
    """This class represents a simple Square object."""

    def __init__(self, size, pos, pen_size=2, pen_color="red", fill_color="blue"):
        """Constructor - create an instance of Square."""
        self._size = size
        self._pos = pos
        self._pen_size = pen_size
        self._pen_color = pen_color
        self._fill_color = fill_color

    def set_color(self, color):
        self._fill_color = color

    def get_color(self):
        return self._fill_color

    def is_in(self, pos):
        """
        Determine whether coordinates are within the area of this Square.
        """
        return self._pos[0] < pos[0] < self._pos[0] + self._size and self._pos[1] < pos[1] < self._pos[1] + self._size

    def draw(self, canvas):
        """
        calls canvas.draw_image() to display self on canvas.
        """
        points = [(self._pos[0], self._pos[1]), (self._pos[0] + self._size, self._pos[1]),
                  (self._pos[0] + self._size, self._pos[1] + self._size), (self._pos[0], self._pos[1] + self._size)]
        canvas.draw_polygon(points, self._pen_size, self._pen_color, self._fill_color)

    def __str__(self):
        return "Square: {}".format(self._pos)


def draw(canvas):
    for square in squares:
        square.draw(canvas)


def change_colors():
    for square in squares:
        # time.sleep(1) # Not implemented in CodeSkulptor and would'nt work anyway
        square.set_color("green")


frame = simplegui.create_frame(TITLE, FRAME_WIDTH, FRAME_HEIGHT)
frame.set_draw_handler(draw)

width = 20
squares = []
for i in range(10):
    squares.append(Square(width, (i * width, 0)))

change_colors()

frame.start()

Any help appreciated.

Robin Andrews
  • 3,514
  • 11
  • 43
  • 111

1 Answers1

1

Yes, you need to use a timer. Something like this:

I = 0

def change_next_color():
    if I < len(squares):
        squares[I].set_color("green")
        global I
        I += 1

timer = simplegui.create_timer(1000, change_next_color)
timer.start()

http://www.codeskulptor.org/#user47_udyXzppCdw2OqdI.py

I also replaced simplegui.Frame._hide_status = True by simplegui.Frame._hide_controlpanel = True

https://simpleguics2pygame.readthedocs.io/en/latest/simpleguics2pygame/frame.html#SimpleGUICS2Pygame.simpleguics2pygame.frame.Frame._hide_controlpanel

See also _keep_timers option of SimpleGUICS2Pygame to help you:

https://simpleguics2pygame.readthedocs.io/en/latest/simpleguics2pygame/frame.html#SimpleGUICS2Pygame.simpleguics2pygame.frame.Frame._keep_timers

Possible improvements:

  • Find a better solution that don't use a global counter.
  • Stop timer when all work is finished.
Olivier Pirson
  • 737
  • 1
  • 5
  • 24
  • Thanks @Olivier. I made some progress using this approach. I've made a working implementation, but there is a problem in that each `tick` of the timer displays an update for all available directions. Would you be willing to take a look at the repo and maybe raise an issue there or even do a pull request? https://github.com/Robin-Andrews/Searching-Algorithms-Visualiser-in-Python – Robin Andrews Jan 18 '20 at 15:42
  • I don't know what your program must be do, but I think there you have a problem in the loop in `thick()` function. In each call of `thick()` the loop can generate several mouvement. I sent a pull request with a simple additional `break` in the loop to avoid that. I guess is not enough to have the correct behaviour, but now there is only one mouvement in each call of `tick()`. – Olivier Pirson Jan 18 '20 at 21:31