Home > Back-end >  python - Conway's Game of Life bug at calculating neighbors, and therefore gets wrong results
python - Conway's Game of Life bug at calculating neighbors, and therefore gets wrong results

Time:05-28

I'm trying to built 'Conway's Game of Life' but for some reason the number of neighbors are not calculated correctly, therefore I gets wrong results. please help me:)

I'm pretty lost I don't know what's wrong...

example that I tried and just make the board blank

[[1, 1, 0, 0, 0], [0, 1, 1, 1, 0], [0, 0, 0, 1, 1], [1, 1, 0, 1, 1], [0, 1, 0, 1, 0]]


| * | * | | | |


| | * | * | * | |


| | | | * | * |


| * | * | | * | * |


| | * | | * | |


def userinp(size_):
"""
    create the matrix by taking user input on board with user default range size.
    :return: a matrix (lists inside a list)
"""
    matrix = []

    for i in range(size_):
        line = []
        for j in range(size_):
            cell = int(input(f"Row {i   1} column {j   1} : "))
            line.append(cell)
        matrix.append(line)
        if i == size_ - 1:  # when reach limit of rows & lines we stop asking from the user an input.
            continue
        else:
            print(f"line {i 1} submitted. continue to line {i 2} : ")

    return matrix


def draw(board, size):
    """
    draw the board by user input (board) of matrix and games rules.
    """
    for i in range(size):
        print(" ---" * size)
        for j in range(size):
            if board[i][j] == 0:
                print("|   ", end='')
            elif board[i][j] == 1:
                print("| * ", end='')
            if j == size - 1:
                print("|")
        if i == size - 1:
            print(" ---" * size)


def calc_cell(old_status, size, matrix, row, col, new_status=0, neighbors=0):
    """
    calculate neighbors and return the new value of the cell.

    :param old_status: boolean value represent if the cell alive or dead
    :param new_status: the new value that will be returned to the cell
    :param size: size of matrix
    :param matrix: the data of the matrix
    :param row: the row of the cell The function check
    :param col: the column of the cell the function check
    :param neighbors: number of the live neighbors of the cell.
    :return: '1' if alive or '0' if dead.
    """
 # check all the cells around the cell, before checking the cells I check if the neighbor cell is in our range.
    if row - 1 >= 0 and col - 1 >= 0:
        if matrix[row-1][col-1] == 1:
            neighbors  = 1

    elif row - 1 >= 0:
        if matrix[row-1][col] == 1:
            neighbors  = 1

    elif row - 1 >= 0 and col   1 < size:
        if matrix[row-1][col 1] == 1:
            neighbors  = 1

    elif col - 1 >= 0:
        if matrix[row][col-1] == 1:
            neighbors  = 1

    elif col   1 < size:
        if matrix[row][col 1] == 1:
            neighbors  = 1

    elif col - 1 >= 0 and row   1 < size:
        if matrix[row 1][col-1] == 1:
            neighbors  = 1

    elif row   1 < size:
        if matrix[row 1][col] == 1:
            neighbors  = 1

    elif col   1 < size and row   1 < size:
        if matrix[row 1][col 1] == 1:
            neighbors  = 1

    print(f"neighbors = {neighbors}")  # todo: delete
    # check by the rules of the game what is the new status of the cell.
    alive = old_status

    if alive and neighbors <= 1:
        new_status = 0

    elif neighbors > 3:
        new_status = 0

    elif not alive and neighbors == 3:
        new_status = 1

    elif alive and (neighbors == 2 or neighbors == 3):
        new_status = int(old_status)  # convert the boolean value to '0' or '1' (integers)

    return new_status


def main():
    s = int(input("Please enter the size of the board (rows = columns): "))
    print("Please enter input for stating the game.\nInput is '1' for a live cell and 
'0' for dead cell.")
    b = userinp(s)  # my board, a matrix.
    draw(b, s)

    # start checking cells status
    while True:
        # create empty matrix to store updated values
        line = [0 for _ in range(s)]
        new_mat = [line for _ in range(s)]
        # put new values in new matrix
        for row in range(s):
            for col in range(s):
                new_mat[row][col] = calc_cell(old_status=bool(b[row][col]), size=s, matrix=b, row=row, col=col)
            print(b)  # todo: delete

        draw(new_mat, s)
        q = input("would you like the program to continue calculating the board? (type yes / no): ").lower()
        if 'n' in q:
            break
        else:
            b = new_mat


if __name__ == '__main__':
    main()

CodePudding user response:

In the series of if and elifs, at most one of them will get executed, which means neighbors is either 0 or 1.

You may replace elifs with ifs, but I would recommend at least using some loops to simplify the code:

for dx in [-1, 0, 1]:
    for dy in [-1, 0, 1]:
        # For the 3x3 square around the cell
        if (0 <= col   dx < size) and (0 <= row   dy < size):
            if (dx != 0 or dy != 0) and matrix[row   dy][col   dx] == 1:
                # Excludes the cell itself
                neighbors  = 1

There is another bug in your code:

line = [0 for _ in range(s)]
new_mat = [line for _ in range(s)]

Now new_mat is a list of entries all pointing to the same line, which means modifying one line will effectively modify all the line. Instead, use:

new_mat = [[0 for _ in range(s)] for _ in range(s)]
  • Related