3
\$\begingroup\$

I'm totally new to python and coding in general and I tried for my first project to recreate Conway's game of life. After days of trial and error, I came up with this code:

import numpy as np 
import copy 
import png    
import PIL as PIL
def a(a) : 
    if a == "gen" : 
        size=int(input("size ? ")) 
        ratio=float(input("ratio ? ")) 
        name=input("file name: ") 
        matrix=np.random.choice(2,(size,size),p=[1-ratio,ratio])
        i = png.from_array(matrix, mode='L;1')
        i.save(str(name)+'.JPEG')

    if a == "start" : 
        name=input("file name: ") 
        time=input('number of rounds: ')
        matrix=np.asarray(PIL.Image.open(str(name)+'.jpeg')).astype(int) 
        matrix2=copy.deepcopy(matrix)
        taille1,taille2=matrix.shape 
        counter=0 
        while counter<int(time): 
           for x in range(0,taille1-1):
             for y in range(0,taille2-1):
                if matrix[x,y]==0 and matrix[x+1,y]+matrix[x,y+1]+matrix[x+1,y+1]+matrix[x-1,y]+matrix[x,y-1]+matrix[x-1,y-1]+matrix[x-1,y+1]+matrix[x+1,y-1]==3:
                   matrix2[x,y]=1 
                if matrix[x,y]==1 and matrix[x+1,y]+matrix[x,y+1]+matrix[x+1,y+1]+matrix[x-1,y]+matrix[x,y-1]+matrix[x-1,y-1]+matrix[x-1,y+1]+matrix[x+1,y-1]<2:
                   matrix2[x,y]=0  
                if matrix[x,y]==1 and matrix[x+1,y]+matrix[x,y+1]+matrix[x+1,y+1]+matrix[x-1,y]+matrix[x,y-1]+matrix[x-1,y-1]+matrix[x-1,y+1]+matrix[x+1,y-1]>3:
                   matrix2[x,y]=0  
           i = png.from_array(matrix2, mode='L;1')
           i.save(str(name)+'_output_'+str(counter+1)+'.JPEG')
           matrix=copy.deepcopy(matrix2)
           counter+=1
task=input("command : ")
a(task)    

It works really fine but I'm afraid it is quite unefficient, so I'd like to hear advice on how to make it faster (especially the triple loop)

\$\endgroup\$

1 Answer 1

3
\$\begingroup\$

First of all, please try to reformat the Python code according to Python's style guide (PEP 8).

When programming, it is important to give meaningful names to all variables (with exception to some loop indexes). What is a? Or taille1? My strong believe is, that even "research" kind of programming can benefit from this advice. Try using good Python IDE, eg, PyCharm, which will help to autocomplete names. Programs are read by humans.

It's better to convert user input to the proper type immediately, no need to do it each time in while loop. Similarly, it makes program more readable if input/output is separated from computations.

Also, I do not quite understand why do you want deep copy the matrix each time. Perhaps, more efficient strategy is to have two arrays and alternate them.

As for the computational part, I'd suggested the following simplification:

  • instead of computing the sum or surrounding cells several times, do it just once. You can add current cell multiplied by eg 10 so the sum will be a single parameter.

You can also have precomputed rules:

RULES = {
    1: 0,
    2: 0,
    3: 1,
    4: 0,
    ...
    10: 0,  # tens indicate current cell
    12: 1,  # continues to live
    13: 1,  #
    14: 0,  # dies due to overpopulation
    15: 0,
    ...
}

Then deciding cell's fate can be done very efficiently:

matrix[x, y] = RULES[weighted_sum]

Of course, this is quite small optimization, but it makes possible to implement any cellular automaton by just changing rules in one place.

Also, pay attention to border conditions. Padding of zeros on each side is needed for the algorithm to work correctly.

Offtopic note: The question made me nostalgic: I remember how still a schoolboy I've found a BASIC program for the Game of Life in Peter Atkins's book "The Second Law" (I read it in translation), and wondered how inefficient implementation it had. Border conditions were checked for each neighbor instead of padding zeros. I do not remember now how the sum was calculated, but this answer actually repeats my idea from that time - single array lookup (in Basic). In Python, of course, there are dicts for O(1) computation.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Ok thanks a lot ! I'll apply your advice ! I was indeed going to pad zeros but I had never thought of using two alternating matrices. If names seem unclear it's mostly because everything was originally in french. \$\endgroup\$
    – Hugo J.
    Commented Jul 21, 2018 at 14:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.