Danny Yoo wrote:
(Aside: one nonobvious example where copying can be avoided is in
Conway's Game of Life:  when we calculate what cells live and die in
the next generation, we can actually use the 'Command' design pattern
to avoid making a temporary copy of the world.  We can talk about
this in more detail if anyone is interested.)

Just as a warning, none of what I'm going to code here is original at all: I'm rehashing a main idea off of a paper called "Using the Game of Life to Introduce Freshman Students to the Power and Elegance of Design Patterns":

http://portal.acm.org/citation.cfm?id=1035292.1028706

Uh, with all respect Danny, this is a nice example of the Command pattern, but to me this example would better be called "Using the Power and Elegance of Design Patterns to Complicate the Game of Life".


Now the problem is: given the current state of the world, how do we
calculate the next state of the world?  One way is to make a temporary
copy of the world, and apply changes to it, consulting the original
world for the rules:

###
def apply_next_generation(world):
    """Destructively mutate the world so it reflect the next
    generation."""
    M, N = world['dimensions']
    new_world = copy.copy(world)
    for j in range(N):
        for i in range(M):
            if is_born(world, i, j):
                new_world[i, j] = LIVE
            if is_deceased(world, i, j):
                new_world[i, j] = DEAD
    for j in range(N):
        for i in range(M):
            world[i, j] = new_world[i, j]
###

Why not just build a new world with the values of the next generation in it, and return that from apply_next_generation? The copying is not needed at all and the command pattern is introduced to solve a non-problem. Something like this:


 def apply_next_generation(world):
     """Destructively mutate the world so it reflect the next
     generation."""
     new_world = {}
     new_world['dimensions'] = world['dimensions']
     M, N = world['dimensions']
     for j in range(N):
         for i in range(M):
             if is_born(world, i, j):
                 new_world[i, j] = LIVE
             if is_deceased(world, i, j):
                 new_world[i, j] = DEAD
     return new_world

The caller would have to change slightly to accept the new world returned from the function, but there is no unnecessary copying.

This is very similar to Dave's situation that kicked of the thread, where he was using a copy instead of a simple assignment and regeneration.

If you want to avoid creating a new world each time you could have two worlds and bounce back and forth between them.

Kent
_______________________________________________
Tutor maillist  -  Tutor@python.org
http://mail.python.org/mailman/listinfo/tutor

Reply via email to