I recently saw a video of an implementation of Conway’s game of life written in APL which was done in just one line. And because I couldn’t sleep last night, I implemented it in python as short as I possibly could.

So here it is:

1 2 3 4 |
def evolution(life,s=size,next=0): for j,i,nb in map(lambda j:(j,j+s+1,bin(life&((7|5<<s|7<<s*2)<<j))[2:].count('1')),map(lambda x:x+int(x/(s-2))*2,range(0,(1<<s-2)+1))): next = next|(1<<i)^(1^(((('23'.count(str(nb))<<1)+'3'.count(str(nb)))>>((life>>i)&1))&1))<<i return next |

There’s a little write-up and the source after the break.

It isn’t exactly readable nor pretty, but it works. Unfortunately there are several caveats I didn’t get around: The function expects a number as input *life*, whereas the binary representation of that number is a two dimensional array with 1 representing a live cell and 0 a dead cell. Also the function expects those numbers to be padded with zeros on the outside. The third problem is, that it currently only works for arrays of the size n².

So to create a game, one first has to find the number that represents the initial status and its size. Thats easy:

1 2 3 4 5 6 7 |
size = 5 life = int(''' 00000 00100 00100 00100 00000'''.replace('n',''),2) |

It seems to work reasonably well for small fields but I guess that the way python handles really large numbers is the reason for a sudden performance hit for a field with the size of around 20.

# On the code:

I used a few tricks to reduce the number of lines, without calculating things multiple times. For example, I am using a bit mask to find out which neighbors are alive:

1 |
life&((7|5<<s|7<<s*2)<<j) |

7 in binary is 111, 5 is 101 and 7 is again 111. I then shifted the bits so that the mask would align to the size of the field. Then I perform a bitwise logical-and with the mask shifted by *j* which is my array index. This gives me a number that has as many ones in binary representation as *j* has neighbors. So to count the neighbors I convert the number using to a binary representation and count how many times the character ‘1’ is inside that string:

*bin(5) *gives *‘0b101’* which means 2 neighbors, so I count count them like this: *bin(7)[2:].count(‘1’)*

You can have a look at the source code and play around with it (game-of-life-3liner.zip). There are two other figures inside the code to try out.