Game of life, what's wrong? [closed]

1

I'm training Python and recently I've been trying to recreate the famous "Game Of Life", I've managed to avoid code failures but it still is not behaving correctly. The program was supposed to behave this way:
link

Note that the game is still running through the console window and is best viewed by the default console and has not yet implemented any editing functions so the grid is randomly generated. link

def genhash(sizex=10, sizey=10):
    hash = {}
    hash["sizex"] = sizex
    hash["sizey"] = sizey

    for x in range(sizex):
        for y in range(sizey):
            hash[(x, y,)] = 0
    return hash


def hashprint(h, char0="0", char1="1"):
    if "sizex" in list(h.keys()) and "sizey" in list(h.keys()):

        x = h["sizex"]
        y = h["sizey"]
        p = ""

        for xx in range(x):
            for yy in range(y):

                p = p + (str(h[(xx, yy)]))
            p = p + ("\n")
        return p.replace("0", char0).replace("1", char1)
    else:
        raise ValueError("the argument is not a spatial hash")


def randomhash(h, rate):
    if "sizex" in list(h.keys()) and "sizey" in list(h.keys()):
        from random import random

        x = h["sizex"]
        y = h["sizey"]
        newh = {}
        newh["sizex"] = x
        newh["sizey"] = y

        for x1 in range(x):
            for y1 in range(y):

                r = random()
                v = 0
                if r < rate:
                    v = 1
                else:
                    v = 0
                newh[(x1, y1)] = v

        return newh
    else:
        raise ValueError("the argument is not a spatial hash")


def convolute(h, r="b3s23"):
    if "sizex" in list(h.keys()) and "sizey" in list(h.keys()):

        # rules
        rb = r.find("b")
        rs = r.find("s")

        b = [int(rule) for rule in r[rb + 1:rs]]
        s = [int(rule) for rule in r[rs + 1:]]

        # x,y !!
        x = h["sizex"]
        y = h["sizey"]

        for xxx in range(x):

            # torus wrapping
            xp1 = xxx + 1
            xm1 = xxx - 1

            if xp1 > x - 1:
                xp1 -= x

            if xm1 < 0:
                xm1 += x

            for yyy in range(y):

                # torus wrapping
                yp1 = yyy + 1
                ym1 = yyy - 1

                if yp1 > y - 1:
                    yp1 -= y

                if ym1 < 0:
                    ym1 += y

                # compute sum of neighbor cells
                sum = (h[(xm1, yp1)] +
                       h[(xxx, yp1)] +
                       h[(xp1, yp1)] +
                       h[(xm1, yyy)] +
                       h[(xp1, yyy)] +
                       h[(xm1, ym1)] +
                       h[(xxx, ym1)] +
                       h[(xp1, ym1)])

                # apply rules
                if h[(xxx,yyy)] == 0:
                    if sum in b:
                        h[(xxx,yyy)] = 1
                else:
                    if sum not in s:
                        h[(xxx,yyy)] = 0


    else:
        raise ValueError("the argument is not a spatial hash")


if __name__ == "__main__":

    h = genhash(20, 40)
    h = randomhash(h, 0.2)

    import time


    while 1:
        time.sleep(0.1)
        convolute(h)
        print(hashprint(h, " ", "5"),"console preview")
    
asked by anonymous 24.01.2017 / 02:51

1 answer

3

Ok - Your question is not well formulated in the sense that it does not speak exactly what the error is.

As a half-fan of the game of life, I persisted a little bit - it was only when I created a function that populated your matrix with a "mover" just like the example you point to - there in fact we have a different behavior.

Then instead of your randomhash function by:

def moverhash(h):
    [h.__setitem__((x,y), 0) for x in range(h['sizex']) for y in range(h['sizey'])]
    h[10, 10] = 1
    h[10, 11] = 1
    h[10, 12] = 1
    h[9, 12] = 1
    h[8, 11] = 1

This draws the specific form you should go "walking" down. (And apart from that, you can use tuples (in this case, pairs) as dictionary indexes without using a couple of parentheses inside the bracket)

In addition to this function, I put a pause between generations - since your program is a console, a simple% of% within input() , at the end, lets just move to the next frame by pressing while / p>

But anyway, it's easy to see that it's wrong - and the more attention we get, the better: You are updating every cell in the array while you are scanning - but you are querying the same array you are changing. That way, when you arrive at the (y + 1) column, the cells it queries for neighbor in column (y) are already with the next generation values. (another detail: your "x" is vertical, and your "y" horizontally, denoting columns)

That is: by computing the neighbors of each cell, you count half of the grid in the previous generation, and the other half of the cells already computed for the next generation.

This is easily solved by changing your <enter> to receive the old grid, create and populate a new grid, and return the new grid with each interaction:

def convolute(h, r="b3s23"):
    if "sizex" not in h or "sizey" not in h:
        raise ValueError("the argument is not a spatial hash")

    # rules
    rb = r.find("b")
    rs = r.find("s")

    b = [int(rule) for rule in r[rb + 1:rs]]
    s = [int(rule) for rule in r[rs + 1:]]

    new_grid = {}
    # x,y !!
    x = new_grid['sizex'] = h["sizex"]
    y = new_grid['sizey'] = h["sizey"]

    for xxx in range(x):

        # torus wrapping
        xp1 = xxx + 1
        xm1 = xxx - 1

        if xp1 > x - 1:
            xp1 -= x

        if xm1 < 0:
            xm1 += x

        for yyy in range(y):

            # torus wrapping
            yp1 = yyy + 1
            ym1 = yyy - 1

            if yp1 > y - 1:
                yp1 -= y

            if ym1 < 0:
                ym1 += y

            # compute sum of neighbor cells
            sum_ = sum((
                    h[xm1, yp1],
                    h[xxx, yp1],
                    h[xp1, yp1],
                    h[xm1, yyy],
                    h[xp1, yyy],
                    h[xm1, ym1],
                    h[xxx, ym1],
                    h[xp1, ym1]))

            # apply rules
            if not h[(xxx,yyy)]:
                new_grid[xxx,yyy] = int(sum_ in b)
            else:
                new_grid[xxx,yyy] = int(sum_ in s)
    return new_grid

And obviously change the function call:

if __name__ == "__main__":

    h = genhash(20, 40)
    #h = randomhash(h, 0.1)
    moverhash(h)

    while True:
        print(hashprint(h, " ", "5"),"console preview")
        h = convolute(h)
        input()
    
24.01.2017 / 05:39