Игра Конвея жизни, реализованный на языке Python


Я в Python Новичок и решили дать игре Жизнь попробовать в Python 3:

import os
import time
import curses

class Cell:
    newlabel = ''
    def __init__(self,row,col,label):
        self.row = row
        self.col = col
        self.label = label

    def updatecell(self,celllist, boardsize):
        liveneighbours = self.getliveneighbours(celllist, boardsize)
        if liveneighbours < 2 or liveneighbours > 3: #Kills cell if it has <2 or >3 neighbours
            self.newlabel = ' '
        elif liveneighbours == 2 and self.label == ' ': #Cell doesn't come alive if it is dead and only has 2 neighbours
            self.newlabel = ' '
        else: #Cell comes alive if it is already alive and has 2/3 neighbours or if it is dead and has 3 neighbours
            self.newlabel = 0

    def getliveneighbours(self,celllist,boardsize):
        count = 0
        for row in range(self.row-1,self.row+2):
            try:
                celllist[row]
            except:    #Handles vertical wrapping. If there's an error, it checks the wrapped cell
                if row < 0:
                    row += boardsize[0]
                else:
                    row -= boardsize[0]
            for col in range(self.col-1,self.col+2):
                try: #Handles horizontal wrapping. If there's an error, it checks the wrapped cell
                    celllist[row][col]
                except:
                    if col < 0:
                        col += boardsize[1]
                    else:
                        col -= boardsize[1]
                if not celllist[row][col].label:
                    count += 1
        if not self.label: #Subtracts the cell from the neighbours count
            return count-1
        else:
            return count

    def updatelabel(self): #Updates the cell's label after all cell updates have been processes
        self.label = self.newlabel


class Board:
    celllist = {} #Dict of rows
    def __init__(self, rows, columns):
        self.rows = rows
        self.columns = columns
        self.generate()

    def printboard(self): #Prints the board to the terminal using curses
        for num, row in self.celllist.items():
            line = ''
            for col, cell in enumerate(row):
                line += str(cell.label)
            terminal.addstr(num, 0, line)
        terminal.refresh()

    def generate(self): #Adds all the cells to the board
        for row in range(self.rows-1):
            self.celllist[row] = []
            for col in range(self.columns):
                self.celllist[row].append(Cell(row,col,' '))

    def updateboard(self): #Prompts each cell to update and then update their label
        for row in self.celllist:
            for cell in self.celllist[row]:
                cell.updatecell(self.celllist, (self.rows-1, self.columns))
        for row in self.celllist:
            for cell in self.celllist[row]:
                cell.updatelabel()

if __name__ == "__main__":
    terminal = curses.initscr() # Opens a curses window
    curses.noecho()
    curses.cbreak()
    terminal.nodelay(1) #Don't wait for user input later
    rows, columns = os.popen('stty size', 'r').read().split()
    board = Board(int(rows), int(columns))
    board.celllist[6][8].label = 0
    board.celllist[7][9].label = 0
    board.celllist[7][10].label = 0
    board.celllist[8][8].label = 0
    board.celllist[8][9].label = 0
    while 1:
        board.printboard()
        time.sleep(0.1)
        board.updateboard()
        char = terminal.getch()
        if char == 113: #Checks for ASCII Char code for q and then breaks loop
            break
    curses.endwin() #Closes curses window

Я написала его для работы в зависимости от размера ваших терминалов, и я сделал по бокам обернуть вокруг, потому что это было единственное решение, которое я мог придумать. Также, в конце концов, я включил пример планера в качестве теста.

Вопросы:

  1. Моя реализация для Python достаточно (особенно в отношении квот и мое постоянное использование итерации)?

  2. Структуры данных, которые я использовал для celllist (массивов в дикт) подходит?

  3. Это клянет хороший способ отображения игры? Бы с которым Pygame быть лучше?

  4. Общий стиль код хороший?

  5. Для дальнейшего развития этого, есть лучший алгоритм, который я мог бы реализовать или лучше способ (кроме оборачивать сторон) отображение всех ячеек?



Комментарии
1 ответ


  1. Работает ваш код через pycodestyle будут освещены некоторые вопросы, чтобы сделать код более привычный для Pythonistas. Кроме этого:


    • while 1 должно быть написано как while True (явное лучше, чем неявное)

    • Вместо того, чтобы проверить для конкретного персонажа, чтобы бросить курить, я бы просто предположить, что люди знают про сочетание клавиш Ctrl-с

    • Использовать легко читаемые имена, как это возможно. updatecellнапример, может быть update_cell или даже update так это само собой подразумевается, что это Cell это обновляется.

    • Обычно if __name__ == "__main__": следует просто main() или sys.exit(main()) (наверное, не актуально в вашем случае). Это делает код более проверяемым. Цель-свести к минимуму количество кода верхнего уровня в целом.


  2. Совет-это действительно Матрица, так что ИМО лучше представить это с помощью списка списков или в идеале матрица класса. А dict нет никакого внутреннего порядка, так что семантически это неправильно, что нужно использовать в любом случае.

  3. Кому-то еще придется ответить на этот.

  4. Это слишком субъективно, чтобы ответить.

  5. Некоторые предложения:


    • Старайтесь учитывать тот факт, что в игре жизни доска-это бесконечная во всех направлениях. В идеале реализация должна справиться с этим, но вы могли бы также использовать его в качестве стоп-условие - когда все становится слишком близко к краю, чтобы иметь возможность выяснить, следующий шаг с уверенностью, программа могла остановиться.

    • Вы можете избежать преобразования между числами и строками с помощью чисел или даже булевых везде (например, хранящиеся в value или state поле, а не label). Вы можете потом написать отдельный метод для отображения Boardпреобразование значений для любой пары символов, которые вы хотите, и, возможно, с украшениями.

    • А не обновление Cellв отдельности, сохраняя их новое значение можно заменить весь Board С новое на каждом шагу.

    • В time.sleep() в настоящее время не учитывает, что Board обновление времени может измениться. Это вряд ли будет проблемой для малого совета, но если вы хотите полностью гладкие рамы, вы хотите использовать потоки или жесткий цикл, который проверяет, является ли это время, чтобы напечатать текущую Board еще.


5
ответ дан 3 апреля 2018 в 03:04 Источник Поделиться