Skip to content

Instantly share code, notes, and snippets.

@osa1
Created November 12, 2011 08:46
Show Gist options
  • Save osa1/1360259 to your computer and use it in GitHub Desktop.
Save osa1/1360259 to your computer and use it in GitHub Desktop.
A simple grid class and some helper functions which I wrote to visualize some algorithms
import threading
import pygame
class Grid(object):
def __init__(self, size_x, size_y=None):
if not size_y:
self.size_x = size_x[0]
self.size_y = size_y[1]
else:
self.size_x = size_x
self.size_y = size_y
self.__data = ["" for i in xrange(self.size_x * self.size_y)]
self.__connections = {}
self.__rects = {} # (x, y) : (r, g, b)
self.surface_size = (600, 600)
self.surface = None
self.__last_highlighted_cell = None
pygame.font.init()
self.font = pygame.font.Font("visitor2.ttf", 10)
def get_at(self, x, y):
return self.__data[y * self.size_x + x]
def set_at(self, x, y, val):
self.__data[y * self.size_x + x] = val
def neighbors(self, x, y):
return [(x+xi, y+yi) for xi, yi in ((-1, 0), (0, -1), (1, 0), (0, 1)) \
if x+xi >= 0 and x+xi < self.size_x \
and y+yi >= 0 and y+yi < self.size_y]
def fill(self, x, y, color):
self.__rects[(x, y)] = color
def fill_clear(self, x, y):
del self.__rects[(x, y)]
def connect(self, x1, y1, x2=None, y2=None):
if x2 == None: # 0 != None
x1, y1 = x1
x2, y2 = y1
l = self.__connections.get((x1, y1), [])
if not l:
self.__connections[(x1, y1)] = l
l.append((x2, y2))
def disconnect(self, x1, y1, x2=None, y2=None):
if not x2:
x1, y1 = x1
x2, y2 = y1
self.__connections[(x1, y1)].remove((x2, y2))
def draw_hexagon(self):
width = self.surface.get_width() / self.size_x
height = self.surface.get_height() / self.size_y
for x in xrange(self.size_x):
for y in xrange(self.size_y):
if (y % 2) == 0:
centerx = (width*1.7/2+(width/2))*x + width / 2 # 1.7 is sqrt(3)
centery = height / 2 + max(height * y / 2, 0)
pointlist = [(centerx - width / 2, centery),
(centerx - width / 4, centery - height / 2),
(centerx + width / 4, centery - height / 2),
(centerx + width / 2, centery),
(centerx + width / 4, centery + height / 2),
(centerx - width / 4, centery + height / 2)]
nextx = (width*1.7/2+(width/2))*(x+1)
pygame.draw.aalines(self.surface, (100, 255, 0), True, pointlist)
pygame.draw.aaline(self.surface, (100, 255, 0),
pointlist[3], (nextx, pointlist[3][1]))
def highlight_cell(self, pos):
width = self.surface.get_width() / self.size_x
height = self.surface.get_height() / self.size_y
cellx = pos[0] / width
celly = pos[1] / height
pygame.draw.rect(self.surface, (160, 160, 160),
(width * cellx + 1, height * celly + 1, width-1, height-1))
# FIXME: maybe I should just redraw all screen every frame
if self.__last_highlighted_cell and self.__last_highlighted_cell != (cellx, celly):
pygame.draw.rect(self.surface, (0, 0, 0),
(width*self.__last_highlighted_cell[0]+1,
height*self.__last_highlighted_cell[1]+1, width-1, height-1))
self.__last_highlighted_cell = (cellx, celly)
self.draw()
def draw(self, surface=None):
# TODO: minimize draw count per frame
if not surface:
if not self.surface:
self.surface = pygame.display.set_mode((600, 600), pygame.RESIZABLE, 32)
self.first_draw = False
surface = self.surface
width = self.surface.get_width() / self.size_x
height = self.surface.get_height() / self.size_y
# draw vertex lines
pygame.draw.rect(surface, (100, 255, 0),
(0, 0, width*self.size_x+1, height*self.size_y+1), 1)
for x in xrange(self.size_x):
for y in xrange(self.size_y):
#pygame.draw.aaline(surface, (255, 255, 255), (width*x, height*y),
#(width*x, height*(y+1)))
#pygame.draw.aaline(surface, (255, 255, 255), (width*x, height*y),
#(width*(x+1), height*y))
#pygame.draw.aaline(surface, (255, 255, 255), (width*(x+1), height*y),
#(width*(x+1), height*(y+1)))
#pygame.draw.aaline(surface, (255, 255, 255), (width*(x+1), height*(y+1)),
#(width*x, height*(y+1)))
if (x+y) % 2:
pygame.draw.rect(surface, (100, 255, 0), (width*x, height*y,
width+1, height+1), 1)
t = self.get_at(x, y)
if t:
text = self.font.render(self.get_at(x, y),
True, (255, 255, 255))
surface.blit(text, (width*x, height*y))
# fill vertices
for vertex, color in self.__rects.iteritems():
pygame.draw.rect(surface, color,
(width*vertex[0]+1, height*vertex[1]+1, width-1, height-1))
# draw connection lines
for conn_from, conns in self.__connections.iteritems():
self._draw_conn_rect(conn_from[0], conn_from[1], width, height)
for conn_to in conns:
self._draw_conn_rect(conn_to[0], conn_to[1], width, height)
pygame.draw.aaline(surface, (0, 255, 255),
(conn_from[0]*width+(width/2), conn_from[1]*height+(height/2)),
(conn_to[0]*width+(width/2), conn_to[1]*height+(height/2)), 0)
def _draw_conn_rect(self, x, y, width, height):
pygame.draw.rect(self.surface, (0, 0, 200), (x*width+(width/2)-5,
y*height+(height/2)-5, 10, 10))
def __iter__(self):
return iter(self.__data)
def run():
pygame.display.init()
time = pygame.time.Clock()
g.draw()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
g.surface = None
pygame.display.quit()
return
elif event.type == pygame.VIDEORESIZE:
g.surface = pygame.display.set_mode(event.size, pygame.RESIZABLE, 32)
g.draw()
elif event.type == pygame.MOUSEMOTION:
g.highlight_cell(pygame.mouse.get_pos())
pygame.display.flip()
time.tick(30)
def start():
t = threading.Thread(target=run)
t.start()
return t
MOUSE_ENABLED = True
g = Grid(20, 20)
g.set_at(3, 4, "bok")
g.connect(3, 4, 10, 10)
g.connect(3, 4, 8, 1)
g.fill(5, 5, (255, 255, 255))
g.fill_clear(5, 5)
g.fill(6, 6, (255, 0, 0))
if __name__ == "__main__":
g.draw()
g.draw_hexagon()
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment