Advertisement
eXFq7GJ1cC

Untitled

Aug 28th, 2012
76
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Python 7.44 KB | None | 0 0
  1. """
  2. Comments:
  3.  
  4. The program uses the principle that if a cell did not change this turn and none
  5. of its neighbors changed, then there it won't change this turn and can be
  6. skipped.
  7.  
  8. grid = a boolean 2d array showing the status of all the cells
  9.  
  10. gridNext = a boolean 2d array showing status of all cells in the next generation
  11.  
  12. activeCell = list of tuples showing cells that either changed or had neighbors
  13. that changed this turn. This is the list that we iterate over every generation
  14.  
  15. didChange = list of tuples of active cells which changed this turn
  16.  
  17. didNotChange = list of tuples of active cells which changed this turn.
  18. if none of their neighbors changed either, remove it from the activeCell list
  19. so we won't bother looking at it in the next generation.
  20.  
  21.  
  22. #BASIC LOOP
  23. clear didNotChange()
  24. clear didChange()
  25.  
  26. for each cell in activeCell()
  27.    if alive
  28.        if countOfNeighbors in (LIVERULE)
  29.            add cell to group didNotChange()
  30.        else
  31.            kill
  32.            add all neighbors to group activeCell()
  33.            add cell to group didChange()
  34.    else
  35.        if countofNeighbors in (BIRTHRULE)
  36.            live
  37.            add cell to group didChange()
  38.            add all neighbors to group activeCell()
  39.        else
  40.            add cell to group didNotChange()
  41.  
  42. for each cell in didNotChange()
  43.    if all neighbors of that cell did not change this turn:
  44.        remove cell from group activeCell()
  45.  
  46. for each cell in didChange()
  47.    draw
  48.  
  49. #-----------------
  50. controls:
  51. left mouse button: add cell
  52. s = start / stop
  53. c = clear board
  54. """
  55.  
  56. # Dependencies ---------------------------------------------------------------
  57.  
  58. import pygame, sys
  59.  
  60. def mainloop():
  61.  
  62.     BLACK    = (   0,   0,   0)
  63.     WHITE    = ( 255, 255, 255)
  64.     GREY     = ( 245, 245, 245)
  65.  
  66.     FPS = 60
  67.  
  68.     SIZE = 5                    #cell size, in pixels
  69.     MARGIN = 1                  #space between cells, in pixels
  70.     # WIDTH, HEIGHT = 120, 80     #board width, height, in cells
  71.     WIDTH, HEIGHT = 300, 200    #board width, height, in cells
  72.  
  73.     LIVERULE = (2, 3)   #neighbors needed for a live cell to keep on living
  74.     BIRTHRULE = (3,)    #neighbors needed for a dead cell to become alive
  75.  
  76.     # cells are identified by their integer index, i.e. (r * WIDTH) + c
  77.     # precompute the adjacencies of each cell by index, and the screen
  78.     # rectangles of each cell by index
  79.     adjacencies = [[((r + dx) % HEIGHT) * WIDTH + (c + dy) % WIDTH
  80.         for dx, dy in ((-1, -1), (-1, 0), (-1, 1), (0, -1), (0, 1), (1, -1), (1, 0), (1, 1))]
  81.             for r in range(0, HEIGHT)
  82.                 for c in range(0, WIDTH)]
  83.  
  84.     cellrects = [(MARGIN + (SIZE + MARGIN) * (cell % WIDTH), MARGIN + (SIZE + MARGIN) * (cell / WIDTH), SIZE, SIZE)
  85.         for cell in range(WIDTH * HEIGHT)]
  86.  
  87.     # the grid is a linear 1-D series of bytes (bytearray() is the mutable version of bytes())
  88.     grid = bytearray([0] * WIDTH * HEIGHT)
  89.     gridNext = bytearray([0] * WIDTH * HEIGHT)
  90.  
  91.     activeCells = set()
  92.     didNotChange = set()
  93.     didChange = set()
  94.  
  95.     pygame.init()
  96.     screen = pygame.display.set_mode([((SIZE + MARGIN) * WIDTH - MARGIN),((SIZE + MARGIN) * HEIGHT - MARGIN)])
  97.     pygame.display.set_caption("Game of Life")
  98.     clock = pygame.time.Clock()
  99.     drawrect = pygame.draw.rect
  100.  
  101.     # wipe the board clean. GREY is the margin color
  102.     def clearBoard():
  103.         screen.fill(GREY)
  104.         for cell in range(HEIGHT * WIDTH):
  105.             grid[cell] = 0
  106.             drawrect(screen, BLACK if grid[cell] else WHITE, cellrects[cell])
  107.  
  108.     # this takes a (x, y) address as a convenience
  109.     def changeCell(newstate, x, y):
  110.         cell = y * WIDTH + x
  111.         oldval = grid[cell]
  112.         grid[cell] = newstate
  113.         if oldval != newstate:
  114.             didChange.add(cell)
  115.             activeCells.update([cell], adjacencies[cell])
  116.  
  117.     clearBoard()
  118.  
  119.     if len(sys.argv) == 2 and sys.argv[1] == 'benchmark':
  120.         benchmarking = True
  121.         playing = True
  122.         frametimes = []
  123.         # place a F-pentamino in the center of the board
  124.         centerx, centery = WIDTH / 2, HEIGHT / 2    
  125.         for x, y in ((0, 0), (0, -1), (0, 1), (-1, 0), (1, 1)):
  126.             changeCell(1, x + centerx, y + centery)
  127.     else:
  128.         benchmarking = False
  129.         playing = False
  130.     mousedrag = False
  131.  
  132.     # Event Handler --------------------------------------------------------------
  133.     while True:
  134.         for event in pygame.event.get():
  135.  
  136.             if event.type == pygame.QUIT:
  137.                 pygame.quit()
  138.                 sys.exit()
  139.  
  140.             elif event.type == pygame.KEYDOWN:
  141.  
  142.                 #start / stop game with 's'
  143.                 if event.key == ord('s'):
  144.                     playing = not playing
  145.  
  146.                 #debug: clear board with 'c'
  147.                 elif event.key == ord('c'):
  148.                     clearBoard()
  149.  
  150.             elif event.type == pygame.MOUSEBUTTONDOWN or mousedrag and event.type == pygame.MOUSEMOTION:
  151.                 but = getattr(event, 'button', None) or event.buttons.index(1) + 1
  152.                 mousedrag = True
  153.                 changeCell(1 if but == 1 else 0, event.pos[0] // (SIZE + MARGIN), event.pos[1] // (SIZE + MARGIN))
  154.             elif event.type == pygame.MOUSEBUTTONUP:
  155.                 mousedrag = False
  156.  
  157.         #start / stop game with 's'
  158.         if playing:
  159.             didNotChange.clear()
  160.             didChange.clear()
  161.  
  162.             for cell in tuple(activeCells):
  163.                 neigh = sum(grid[x] for x in adjacencies[cell])
  164.                 if grid[cell]:
  165.                     if neigh in LIVERULE:
  166.                         gridNext[cell] = 1
  167.                         didNotChange.add(cell)
  168.                     else:
  169.                         gridNext[cell] = 0
  170.                         activeCells.update([cell], adjacencies[cell])
  171.                         didChange.add(cell)
  172.                 else:
  173.                     if neigh in BIRTHRULE:
  174.                         gridNext[cell] = 1
  175.                         activeCells.update([cell], adjacencies[cell])
  176.                         didChange.add(cell)
  177.                     else:
  178.                         gridNext[cell] = 0
  179.                         didNotChange.add(cell)
  180.  
  181.             #disable inactive cells (those that did not change this turn)
  182.             for cell in didNotChange:
  183.                 if sum(grid[x] != gridNext[x] for x in adjacencies[cell]) == 0:
  184.                     activeCells.remove(cell)
  185.  
  186.             grid[:] = gridNext[:]
  187.  
  188.         for cell in didChange:
  189.             drawrect(screen, BLACK if grid[cell] else WHITE, cellrects[cell])
  190.  
  191.         pygame.display.update()
  192.         if not benchmarking:
  193.             clock.tick(FPS)
  194.         else:
  195.             frametimes.append(clock.tick())
  196.             if len(frametimes) >= 1500 and benchmarking:
  197.                 f = pygame.font.SysFont('verdana', size=18)
  198.                 msg = '{}x{}: {} frames min={}ms avg={}ms max={}ms total={}ms FPS={:.1f}'.format(
  199.                     WIDTH, HEIGHT, len(frametimes), min(frametimes), sum(frametimes) / len(frametimes),
  200.                     max(frametimes), sum(frametimes), len(frametimes) / (sum(frametimes) / 1000.))
  201.                 print(msg)
  202.                 message = f.render(msg, True, (0, 0, 255))
  203.                 screen.blit(message, ((WIDTH * (SIZE + MARGIN) + MARGIN - message.get_width()) / 2, 50))
  204.                 pygame.display.update()
  205.                 playing = False
  206.                 benchmarking = False
  207.  
  208. mainloop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement