Skip to content

Instantly share code, notes, and snippets.

@iver56
Last active September 26, 2015 21:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save iver56/013ffdf55c58b7562bc7 to your computer and use it in GitHub Desktop.
Save iver56/013ffdf55c58b7562bc7 to your computer and use it in GitHub Desktop.
IT3105: Graphics class for visualizing a 2D grid. Useful when implementing the A* algorithm. Uses pygame.
import sys, pygame
pygame.init()
class Gfx(object):
"""
This class takes care of drawing the state of the search to a window using pygame
"""
size = width, height = 960, 540
WHITE = 255, 255, 255 # undiscovered tiles
BLACK = 0, 0, 0 # closed tiles
YELLOW = 255, 236, 193 # open tiles
GREEN = 47, 160, 19 # goal
GREY = 128, 128, 128 # barriers
BLUE = 109, 142, 224 # start
PINK = 255, 130, 234 # current node
DARK_PINK = 178, 110, 149 # nodes backtracked from current node
def __init__(self, board, fps):
self.board = board
self.GU_X = self.width / float(board.rect.width)
self.GU_Y = self.height / float(board.rect.height)
self.screen = pygame.display.set_mode(self.size)
self.clock = pygame.time.Clock() # used for limiting the fps, so one can see each step
self.fps = fps
def flip_vertically(self, y):
"""
We need to use this because in the specification, (0, 0) is the lower left corner
and not the upper left corner, which is the default when drawing stuff in pygame
:param y:
"""
return self.board.rect.height - 1 - y
def draw_tile(self, x, y, color):
rect = pygame.Rect(
x * self.GU_X + 1,
self.flip_vertically(y) * self.GU_Y + 1,
self.GU_X - 2,
self.GU_Y - 2
)
pygame.draw.rect(self.screen, color, rect)
def draw_barriers(self):
for tile in self.board.inaccessible_tiles:
self.draw_tile(tile[0], tile[1], self.GREY)
def draw_closed_list(self, closed_list):
for tile in closed_list:
self.draw_tile(tile.x, tile.y, self.BLACK)
def draw_open_list(self, open_list):
for tile in open_list:
self.draw_tile(tile.x, tile.y, self.YELLOW)
def draw_start(self):
self.draw_tile(self.board.start.x, self.board.start.y, self.BLUE)
def draw_goal(self):
self.draw_tile(self.board.goal.x, self.board.goal.y, self.GREEN)
def draw_current_node(self, node):
self.draw_tile(node.x, node.y, self.PINK)
def draw_ancestors(self, ancestors):
for ancestor in ancestors:
self.draw_tile(ancestor.x, ancestor.y, self.DARK_PINK)
def draw(self, current_node, ancestors, closed_list, open_list):
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_DOWN:
self.fps /= 2 # halve the fps
if event.key == pygame.K_UP:
self.fps *= 2 # double the fps
if self.fps > 256.0:
self.fps = 256.0
self.clock.tick(self.fps)
self.screen.fill(self.WHITE)
self.draw_barriers()
self.draw_closed_list(closed_list)
self.draw_open_list(open_list)
self.draw_goal()
self.draw_current_node(current_node)
self.draw_ancestors(ancestors)
self.draw_start()
pygame.display.flip()
""" USAGE """
"""
This class assumes that "position" objects are instances of a class with x and y properties, such as this:
class Tile(object):
"""
Each instance of this class holds a position in a 2D world
"""
def __init__(self, x, y):
self.x = x
self.y = y
# current_node is a Tile instance.
# ancestors, closed_list and open_list are collections of Tile instances
# the board variable holds information about width, height, start position, goal position and inaccessible tiles (walls)
gfx = Gfx(board=self.board, fps=30.0)
# for each iteration
gfx.draw(current_node, ancestors, closed_list, open_list) # draw the current state
"""
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment