[Tutor] Re: The Game of Life

Brian van den Broek bvande at po-box.mcgill.ca
Fri Jan 7 00:14:17 CET 2005


Hi all,

after making the sketch I posted a bit ago, I tried to turn to actual
work. But, the bug had bit. ;-) So, here is an attempt at filling out
that sketch in an OOP way. (It is my second OOP program, so if anyone
was so inclined, I'd very much appreciate any comments. Also, I have a 
question about a snag I ran into while debugging.)

I'm also not too used to sharing complete code. I'd put it in the public
domain, but since so much of it was derived from Danny's code, I don't
really know the conventions for so doing. (Were I to know it
appropriate, I'd follow the copyright comment line with:
# This software is released into the public domain.
# Fold, spindle, or mutilate at will

I've attached it rather than pasted it, as with something >100 lines I
don't feel up to shortening line for email. Sorry 'bout that.

The question:

In an earlier version, instead of the run_world() method I now have, I
put the following within my class definition and after (i.e. outside of)
the method defs:
.>    while self.current_generation > self.total_generations:
.>        time.sleep(self.sleep_interval)
.>        self.update_world()
.>        self.print_world()

which caused this:

Traceback (most recent call last):
    File "D:\Python Files\foogame_of_life.py", line 3, in -toplevel-
      class life_world:
    File "D:\Python Files\foogame_of_life.py", line 76, in life_world
      while self.current_generation > self.total_generations:
NameError: name 'self' is not defined

That surprised me -- I'd have guessed that within a class, self was
everywhere defined, and not just within methods.

Clearly, I'm confused about something.

Anyway, thanks for reading. Best to all,

Brian vdB

-------------- next part --------------
# pylife.py
# Version 0.1
# Brian van den Broek
# vanden at gmail.com
# 2005-01-06 Thursday 17:41
# Copyright 2005

'''An OOP and ASCII based representation of Conway's Game of Life.
Much of the code was inspired by a post of Danny Yoo's on 2005-01-03 04:11
to the Python Tutor List. (You can find that post by searching the archives at
<http://mail.python.org/pipermail/tutor/>.)

I make no claims to ellegance or efficency -- this is only the second OOP I
have written.'''

import random, time

class life_world:
    
    def __init__(self, X, Y, sleep_interval = 0.5, total_generations = 20):
        self.X = X
        self.Y = Y        
        self.world = self.seed_world()
        self.sleep_interval = sleep_interval
        self.total_generations = total_generations
        self.current_generation = 0
        self.print_world()
        
    def seed_world(self):
        '''Constructs a new random world of size XxY.'''

        world = {}
        for j in range(self.X):
            for i in range(self.Y):
                world[i, j] = random.choice((True, False))
        return world

    def print_world(self):
        '''Prints out a string representation of a world.'''

        print '\n\nGeneration Number: %s\n' %self.current_generation
        print '--'*(self.Y + 1) + '-'
        for j in range(self.X):
            print '|',
            for i in range(self.Y):
                if self.world[i, j]:
                    print 'X',
                else:
                    print ' ',
            print '|'
        print '--'*(self.Y + 1) + '-'
        
    def count_neighbours(self, cell):
        '''Returns the number of live neighbours to this one.

        'neghboUrs because I'm Canadian, eh.
        '''
        live_count = 0
        i,j = cell
        for i_delta in [-1, 0, 1]:
            for j_delta in [-1, 0, 1]:
                if (i_delta, j_delta) == (0, 0):
                    continue
                try:
                    # To deal with the edges of the matrix, where the
                    # deltas can take us out of bounds.
                    if self.world[i+i_delta, j+j_delta]:
                        live_count += 1
                except KeyError:
                    pass
        return live_count

    def cell_will_change(self, cell):
        '''Returns True if a cell will change, False otherwise.'''
        change = False
        if self.world[cell] and not self.count_neighbours(cell) in (2,3):
            change = True
        if not self.world[cell] and self.count_neighbours(cell) == 3:
            change = True
        return change

    def get_changed_cells_list(self):
        '''Returns a list of cells that will change in the next generation.'''

        changed_cells_list = []
        for c in self.world:
            if self.cell_will_change(c):
                changed_cells_list.append(c)
        return changed_cells_list

    def update_world(self):
        '''Produces the next generation world.'''
        self.current_generation += 1
        changed_cells_list = self.get_changed_cells_list()
        for c in changed_cells_list:
            self.world[c] = not self.world[c]

    def run_world(self):
        while self.current_generation < self.total_generations:
            time.sleep(self.sleep_interval)
            self.update_world()
            self.print_world()

if __name__ == '__main__':
    world = life_world(7, 7)
    world.run_world()



More information about the Tutor mailing list