Search code examples
pythonarraysconways-game-of-lifecellular-automata

Game of Life implementation doesn't work properly in Python


I have a problem with working of my automata - Game of Life. Well, I have an image which I convert to the 2d matrix. On the middle of this image there is an oscilator. As the rules say, the output of this function should be another oscilator but turned by 90 degrees. Unfortunately my output is wrong. You can see on the images below. What's wrong with the code? Could you help me with solving this problem?

def sim():
    tab = cv2.imread(jpg_path, 0)
    tab_x = tab.shape[0]
    tab_y = tab.shape[1]

    new_tab = np.zeros([tab_x, tab_y])

    for x in range(0, tab_x):
        for y in range(0, tab_y):
            if tab[x, y] == 255:
                tab[x, y] = 0
            else:
                tab[x, y] = 1

    #new_tab = tab.copy()

    for x in range(tab_x):
        for y in range(tab_y):
     
            summary = (tab[x, (y-1) % tab_x] + tab[x, (y+1) % tab_x] +
                         tab[(x-1) % tab_x, y] + tab[(x+1) % tab_x, y] +
                         tab[(x-1) % tab_x, (y-1) % tab_x] + tab[(x-1) % tab_x, (y+1) % tab_x] +
                         tab[(x+1) % tab_x, (y-1) % tab_x] + tab[(x+1) % tab_x, (y+1) % tab_x])

            if tab[x, y] == 1:
                if (summary < 2) or (summary > 3):
                    new_tab[x, y] = 0
            else:
                if summary == 3:
                    new_tab[x, y] = 1

    for y in range(0, tab_y):
        for x in range(0, tab_x):
            if new_tab[y, x] == 1:
                new_tab[y, x] = 0
            else:
                new_tab[y, x] = 255

    cv2.imwrite('anMD.jpg', new_tab)

input output

Edit: I'm adding more functions, maybe there is a problem. Now my code looks like this:

def osc(tab, x, y):
    tab[x-1,y-1] = 0
    tab[x-1,y] = 1
    tab[x-1,y+1] = 0
    tab[x,y-1] = 0
    tab[x,y] = 1
    tab[x,y+1] = 0
    tab[x+1,y-1] = 0
    tab[x+1,y] = 1
    tab[x+1,y+1] = 0

    return tab

def gol():
    tab_x = 50
    tab_y = 50

    x = 25
    y = 25

    tab = np.zeros([tab_x, tab_y])
    new_tab = osc(tab, x, y)

    for y in range(0, tab_y):
        for x in range(0, tab_x):
            if new_tab[y, x] == 1:
                new_tab[y, x] = 0
            else:
                new_tab[y, x] = 255

    cv2.imwrite('anMD.jpg', new_tab)
    canvas.delete("all")
    cv2.imwrite('show.jpg', new_tab)
    image = Image.open('show.jpg')
    new_image = image.resize((500, 500))
    new_image.save('show.jpg')
    dimg = ImageTk.PhotoImage(Image.open('show.jpg'))
    canvas.create_image(0, 0, anchor='nw', image=dimg)
    canvas.image = dimg

def sim():
    tab = cv2.imread(jpg_path, 0)
    tab_x = tab.shape[0]
    tab_y = tab.shape[1]

    new_tab = np.zeros_like(tab)

    for x in range(0, tab_x):
        for y in range(0, tab_y):
            if tab[x, y] == 255:
                tab[x, y] = 0
            else:
                tab[x, y] = 1

    for x in range(tab_x):
        for y in range(tab_y):
            """summary = 0
            summary += tab[x - 1, y - 1]
            summary += tab[x - 1, y]
            summary += tab[x - 1, y + 1]
            summary += tab[x, y - 1]
            summary += tab[x, y + 1]
            summary += tab[x + 1, y - 1]
            summary += tab[x + 1, y]
            summary += tab[x + 1, y + 1]"""

            summary = (tab[x, (y-1) % tab_y] + tab[x, (y+1) % tab_y] +
                         tab[(x-1) % tab_x, y] + tab[(x+1) % tab_x, y] +
                         tab[(x-1) % tab_x, (y-1) % tab_y] + tab[(x-1) % tab_x, (y+1) % tab_y] +
                         tab[(x+1) % tab_x, (y-1) % tab_y] + tab[(x+1) % tab_x, (y+1) % tab_y])

            if tab[x, y] == 1:
                if (summary < 2) or (summary > 3):
                    new_tab[x, y] = 0
                else:
                    new_tab[x, y] = 1
            else:
                if summary == 3:
                    new_tab[x, y] = 1

    for y in range(0, tab_y):
        for x in range(0, tab_x):
            if new_tab[y, x] == 1:
                new_tab[y, x] = 0
            else:
                new_tab[y, x] = 255

    for x in range (tab_x):
        for y in range (tab_y):
            tab[x, y] = new_tab[x, y]

    cv2.imwrite('anMD.jpg', new_tab)
    cv2.imwrite('show.jpg', new_tab)
    image = Image.open('show.jpg')
    new_image = image.resize((500,500))
    new_image.save('show.jpg')
    canvas.delete("all")
    dimg = ImageTk.PhotoImage(Image.open('show.jpg'))
    canvas.create_image(0, 0, anchor='nw', image=dimg)
    canvas.image = dimg

That's ORIGINAL 50x50 input and output. original input original output


Solution

  • I notice that you seem to be reading and writing your images in the JPEG format, and that your image reading code treats every pixel that isn't pure white (255) as a live cell.

    JPEG is a lossily compressed image format, which means that the pixel values you get back from reading an image file typically won't be exactly the same as what you wrote into the file. In particular, when the original image contains sharp boundaries between highly contrasting colors, there will typically be fringing and other compression artifacts near those boundaries in the JPEG compressed version. When parsed by your code, this fringing will cause additional live cells to appear near your patterns.

    (To confirm that this is an issue, try removing the CA simulation code entirely and just copying the cell states from tab to new_tab unchanged. Your output image probably won't match the input.)

    If you insist on using the JPEG format, you should change the if tab[x, y] == 255 condition in your image reading code to something more robust like if tab[x, y] > 127. You should also strongly consider using a different image format, such as PNG, for this purpose.

    Ps. As a general tip, you could've figured this issue out yourself if you'd tested your code with very small images (say, 8 by 8 pixels or smaller) and either printed out the contents of your tab / new_tab arrays at various points in your code or, better yet, stepped through your code in a debugger and used it to examine the arrays.