@MAGistr_MTM
Учусь программировать

Что не так в игре «Жизнь»?

Доброе время суток.

Я вовсе недавно сел изучать Python и вот решил создать игру "Жизнь"(линк Вики). Но что-то не работает, точнее все работает, но не верно. Если у кого-то будет время и охота взглянуть на мой код, милости прошу.
Буду очень благодарен за помощь, а также за конструктивную критику кода.
Вот мой код:
def neighbors(row, col, matrix):
    """returns all neighbors of the cell as a list"""
    
    n = len(matrix)
    m = len(matrix[0])
    return [matrix[r][c] for r in range(max(row - 1, 0), min(n, row + 2)) for c in range(max(col - 1, 0), min(m, col + 2)) if r != row or c != col]


def add_zero_frame(matrix):
    """adds frame of zeros around matrix"""
    
    n = len(matrix)
    m = len(matrix[0])
    res = [[0 for j in range(m+2)] for i in range(n+2)]
    
    for i in range(n+1):
        for j in range(m+1):
            if not(i == 0 or j == 0 or i == n+1 or j == m+1):
                res[i][j] = matrix[i-1][j-1]
    return res
    
    
def find_matrix(matrix):
    """finds smallest array without empty rows/colums"""
    
    min_row = len(matrix)
    min_col = len(matrix[0])
    max_row = max_col = 0
    
    for i in range(len(matrix)):
        for j in range(len(matrix[0])):
            if matrix[i][j]:
                min_row = min(min_row, i)
                min_col = min(min_col, j)
                max_row = max(max_row, i)
                max_col = max(max_col, j)
                
    return [[row[min_col:max_col + 1]] for row in matrix[min_row:max_row + 1]]


def game_life(cells, generations):
    start = add_zero_frame(cells) 
    
    for gen in range(generations):
        end = [row[:] for row in start[:]]
        for i in range(len(start)):
            for j in range(len(start[0])):
                neighb = sum(neighbors(i, j, start))
                if start[i][j]:
                    if  2 <= neighb <= 3:
                        end[i][j] = 1
                    else:
                        end[i][j] = 0
                else:
                    if neighb == 3:
                        end[i][j] = 1
        start = add_zero_frame(find_matrix(end))
    
    return find_matrix(start)

П. С. Извините за мой плохой русский и Python)

=========================UPDATE==========================
Найдена ошибка в строке:
return [[row[min_col:max_col + 1]] for row in matrix[min_row:max_row + 1]]

Эта строка возвращала не ту стуктуру данных. Должно быть так:
return [row[min_col:max_col + 1] for row in matrix[min_row:max_row + 1]].
  • Вопрос задан
  • 1329 просмотров
Пригласить эксперта
Ответы на вопрос 2
@Oxoron
Шарпер
Не совсем понял Ваш набор методов (функций).
По факту, вся игра на поле nxn состоит из следующих этапов
1. Создаем матрицу (n+2, n+2), все элементы нулевые.
2. Заполняем некоторые клетки (не крайние) единицами, создавая начальную популяцию.
3. Делаем ходы по следующему алгоритму:
3.1 Сначала для каждой не крайней клетки считаем кол-во соседей (результаты сохраняем в отдельную матрицу).
3.2 В зависимости от числа соседей обращаем клетку в ноль или единицу.

То есть, Вам нужны методы:
1. Заполнить всё поле нулями.
2. Проверка поля на "крайность".
3. Метод создания начальной популяции.
4. Метод подсчета числа соседей.
5. Метод изменения значения клетки в зависимости от числа соседей.
Методы 2, 3, 4, 5 покрываем модульными тестами (Unit-tests)

Самая частая ошибка в реализации заключается в том, что клетку изменяют сразу после подсчета её соседей. Если не ошибаюсь, она у Вас есть.
Плюс, в методе find_matrix вы max_col присваиваете 0, а min_col присваиваете размер массива. Наверное, стоило сделать наоборот.
Непонятно, чего Вы пытаетесь добиться строкой res[i][j] = matrix[i-1][j-1] в Add_zero_frame.
Ответ написан
bobrovskyserg
@bobrovskyserg
Неудачные структуры данных, всё громоздкое.
Поле обязательно растёт каждый шаг - плохо.

from collections import Counter

def display(t, gen):
    sz = 10
    sz2 = sz * 2
    space = [["  "] * sz2 for i in range(sz2)]
    for x, y in gen:
        if sz > x >= -sz <= y < sz:
            space[y + sz][x + sz] = "()"
    for row in space:
        print(''.join(row))
    print("{:>3n}".format(t), "--" * sz2)

def game_life(cells, generations):
    gen = set((x, y) for y, row in enumerate(cells) for x, cell in enumerate(row) if cell)
    for t in range(generations):
        display(t, gen)
        ngh = Counter((x + i, y + j) for x, y in gen for i in range(-1, 2) for j in range(-1, 2))
        gen = set(xy for xy, cnt in ngh.items() if cnt == 3 or cnt == 4 and xy in gen)

# game_life([[1, 1, 1]], 5) # палка
# game_life([[1, 1], [1, 1]], 5) # квадрат
game_life([[1, 1, 1], [0, 0, 1], [0, 1, 0]], 40)  # планер
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы