简体   繁体   中英

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

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()

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

You may replace elif s with if s, 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)]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM