[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[pygame] Life with PyGame



Hi, been lurking 'til now.

Got something to show you. After installing Numeric Python I noticed a nice 
optimized implementation of Conway's Game of Life, the one about cellular 
automata. It displays characters on the console, and I thought it would be 
neat to use PyGame, so I stole some code from arraydemo.py and produced the 
attached file.

It doubles the image dimension to make the dots more visible, and starts 
with a random configuration. I did not get quite right the computation of 
the color of the dots, they come out green on 8 bit depth, white on 16 bit, 
and yellow on 24 bit. :^)

Any comments welcome, obviously. Enjoy.


-- 
"I was wondering if there's any kind of definitive nickname for Perl
programmers, the way we call ourselves Pythonistas?" - Aahz Maruch
"Masochists." - Daniel Klein

Nicola Larosa - nico@tekNico.net
#!/usr/bin/env python

# Derived from the life.py example of Numeric Python, and parts of the
# arraydemo.py example of PyGame, on February 17, 2002 by Nicola Larosa
# <nico@tekNico.net>

"""A Python implementation of Conway's Life

Michael Wohlgenannt writes this about Life:
  "For a single cell there are two distinct states, dead and alive. A living
  cell dies of boredom if there are less than two living neighbours (all in
  all there are eight). A dead cell gets back to life again if there are
  exactly three living neighbours. The last rule is that a living cell dies
  if there are more than three living neighbours.
  A lot of cell configurations that can be constructed show a peculiar and
  amusing behaviour. Some stay as they are, dead or alive, some oscillate,
  some even propagate."
"""

# 26 august 1998, Just van Rossum <just@letterror.com>

import sys, time
import pygame
from pygame.locals import *
from Numeric import *
from random import randrange

def life(cells):
    # convert cells to bytes for speed
    cells = cells.astype(Int8)

    # calculate how many neibors each cell has
    neighbors = shift_left(shift_up(cells))
    neighbors = neighbors + shift_up(cells)
    neighbors = neighbors + shift_right(shift_up(cells))
    neighbors = neighbors + shift_left(cells)
    neighbors = neighbors + shift_right(cells)
    neighbors = neighbors + shift_left(shift_down(cells))
    neighbors = neighbors + shift_down(cells)
    neighbors = neighbors + shift_right(shift_down(cells))

    # apply the "Life" rules (see module doc string)
    newcells = logical_or(
            logical_and(
                cells,
                logical_and(
                    less_equal(2, neighbors),
                    less_equal(neighbors, 3)
                )
            ),
            equal(neighbors, 3)
        )

    # If I understood it correctly, with "rich comparisons"
    # the above could look like this:
    #
    # newcells = cell and (2 <= neighbors <= 3) or neighbors == 3
    #
    # Now, wouldn't that be nice...

    return newcells


def shift_up(cells):
    return concatenate((cells[1:], cells[:1]))

def shift_down(cells):
    return concatenate((cells[-1:], cells[:-1]))

def shift_left(cells):
    return transpose(shift_up(transpose(cells)))

def shift_right(cells):
    return transpose(shift_down(transpose(cells)))

def randomcells(size, chance = 10):
    cells = zeros(size, Int8)

    _range = range

    # fill with noise
    for x in _range(size[0]):
        for y in _range(size[1]):
            cells[x][y] = randrange(chance) == 0
    return cells

def showcells(cells, screen, white):
    "displays a surface, waits for user to continue"
    cellsize = array(cells.shape)
    screensize = cellsize*2
    brightup = zeros(cellsize)
    scaleup = zeros(screensize)
    brightup[:,:] = cells[:,:]*white
    scaleup[::2,::2] = brightup[:,:]
    scaleup[1::2,::2] = brightup[:,:]
    scaleup[:,1::2] = scaleup[:,::2]

    pygame.surfarray.blit_array(screen, scaleup)
    pygame.display.update()


def main():
    print "\n*** Press [Ctrl-C] to exit. ***\n"
#    size = (100, 100)
    size = (150, 150)
#    size = (200, 200)
#    size = (250, 250)
    modesize = (size[0]*2, size[1]*2)
    pygame.init()
    screen = pygame.display.set_mode(modesize)
    pygame.display.set_caption("Conway's Game of Life", "Life")
    white = 2 ** screen.get_bitsize() - 1
    cells = randomcells(size, 10)
    try:
        while 1:
            showcells(cells, screen, white)
            cells = life(cells)
    finally:
        pygame.quit()


if __name__ == "__main__":
    main()