Реализация Python перенесенной игре Конвея жизни совет


import random

import rlereader

class Board:
    """Handles the status of all cells."""

    def __init__(self, size):
        self.size = size
        self.grid = self.make_blank_grid()
        self.furthest_col = 0
        self.furthest_row = 0

    def run_turns(self, num_turns):
        """Run a the simulator for a number of turns."""
        while num_turns > 0:
            self.run_turn()
            num_turns -= 1

    def run_turn(self):
        """Run a single turn of the simulator."""
        new_grid = self.make_blank_grid()
        for row in range(0, self.size):
            for col in range(0, self.size):
                new_grid[row][col] = self.get_cell_life(row, col)

        self.grid = new_grid

    def toggle_cell(self, row, col):
        """Toggle the dead or alive status of a single cell."""
        self.grid[row][col] = not self.grid[row][col]

    def check_furthest(self, row, col):
        """Check the furthest processed cell against this one and update if we
near the edge."""
        if row + 1 >= self.furthest_row:
            self.furthest_row = row + 2
        if col + 1 >= self.furthest_col:
            self.furthest_col = col + 2

    def get_cell_life(self, row, col):
        """Return whether a given cell should become dead or alive.

This may update the processed cell boundaries if neccessary."""
        living_neighbours = self.count_living_neighbours(row, col)
        if self.grid[row][col]:
            if living_neighbours in [2, 3]:
                return True
            else:
                self.check_furthest(row, col)
                return False
        else:
            if living_neighbours == 3:
                self.check_furthest(row, col)
                return True
            return False

    def check_cell(self, row, col):
        """Return whether the cell is dead or alive for the current
generation."""
        if row < 0:
            row = self.size - 1
        if row > self.size - 1:
            row = 0

        if col < 0:
            col = self.size - 1
        if col > self.size - 1:
            col = 0

        return self.grid[row][col]

    def count_living_neighbours(self, row, col):
        """Find how many neighnours of a given cell are alive."""
        active_count = 0
        to_check = [
            (row - 1, col - 1), # Top left
            (row - 1, col), # Top
            (row - 1, col + 1), # Top right
            (row, col - 1), # Left
            (row, col + 1), # Right
            (row + 1, col - 1), # Bottom left
            (row + 1, col), # Bottom
            (row + 1, col + 1) # Bottom Right
        ]

        for crow, ccol in to_check:
            if self.check_cell(crow, ccol):
                active_count += 1

        return active_count

    def make_blank_grid(self):
        """Returns a blank grid for future use."""
        grid = []
        for row in range(0, self.size):
            grid.append([])
            for col in range(0, self.size):
                grid[row].append([])
                grid[row][col] = False
        return grid

    def load_rle_into_grid(self, rle):
        """Loads a RLE representation of a playing field into the grid.

rle should be a file like object."""
        reader = rlereader.GRLEReader()
        data = reader.read_rle(rle) # Returns an uncompressed series of tokens from an rle file. The rle file is opened elsewhere than this package.

        self.blank_grid()

        current_token = 0

        current_row = 0
        current_col = 0
        while True:
            try:
                token = data[current_token]
            except IndexError:
                break # Out of tokens
            if type(token) == rlereader.EOFToken:
                break
            if token.value in ['b', 'o']: # 'o' = alive' 'b' = dead
                self.grid[current_row][current_col] = (token.value == 'o')
                current_col += 1
                if current_col > self.size - 1:
                    print('Too wide an import, cancelling import.')
                    break
                if current_col >= self.furthest_col:
                    self.furthest_col = current_col + 2
            if token.value == '$': # $ indicates end of line.
                current_row += 1
                if current_row > self.size - 1:
                    print('Too high an import, cancelling import.')
                    break
                current_col = 0
                if current_row > self.furthest_row:
                    self.furthest_row = current_row + 2

            current_token += 1

    def randomise_grid(self):
        """Change every cell in a grid to random dead or alive state."""
        for row in range(0, self.size):
            for col in range(0, self.size):
                self.grid[row][col] = random.choice([True, False])

        self.furthest_row = self.size - 1
        self.furthest_col = self.size - 1

    def blank_grid(self):
        """Replace the current grid with a blank grid."""
        self.grid = self.make_blank_grid() 

Это бизнес конце питон игра-симулятор жизни, которую я написал. Я могу получить некоторые мнения о нем? (Надеюсь, это не слишком много, я вырезала все GUI код и rlereader, потому что они не слишком актуальны. blank_grid, randomise_grid и toggle_cell все вызывается только из кода пользовательского интерфейса.



3496
10
задан 7 мая 2011 в 06:05 Источник Поделиться
Комментарии
1 ответ

import random

import rlereader

class Board:
"""Handles the status of all cells."""

def __init__(self, size):
self.size = size
self.grid = self.make_blank_grid()
self.furthest_col = 0
self.furthest_row = 0

def run_turns(self, num_turns):
"""Run a the simulator for a number of turns."""
while num_turns > 0:

Использовать для поворота в диапазоне(num_terms) петли вместо цикла while

            self.run_turn()
num_turns -= 1

def run_turn(self):
"""Run a single turn of the simulator."""
new_grid = self.make_blank_grid()
for row in range(0, self.size):

Просто диапазон использования(самовыдвижение.размера), 0 не нужен.

            for col in range(0, self.size):
new_grid[row][col] = self.get_cell_life(row, col)

self.grid = new_grid

def toggle_cell(self, row, col):
"""Toggle the dead or alive status of a single cell."""
self.grid[row][col] = not self.grid[row][col]

def check_furthest(self, row, col):
"""Check the furthest processed cell against this one and update if we
near the edge."""
if row + 1 >= self.furthest_row:
self.furthest_row = row + 2
if col + 1 >= self.furthest_col:
self.furthest_col = col + 2

Написать ее следующим образом:

 self.furthest_row = max(self.furthest_row, row + 2)
self.furthest_col = max(self.furthest_col, col + 2)

Кроме того, функция обновления, а затем проверяет дальше, лучшего названия будет update_furthest

Я не знаю, почему вы добавляете 2 здесь комментарий, объясняющий, что было бы полезно

    def get_cell_life(self, row, col):
"""Return whether a given cell should become dead or alive.

This may update the processed cell boundaries if neccessary."""
living_neighbours = self.count_living_neighbours(row, col)
if self.grid[row][col]:
if living_neighbours in [2, 3]:
return True
else:
self.check_furthest(row, col)
return False
else:
if living_neighbours == 3:
self.check_furthest(row, col)
return True
return False

Написать ее следующим образом:

        living_neighbours = self.count_living_neighbours(row, col)
if self.grid[row][cell]:
new_value = living_neighbors in [2,3]
else:
new_value = living_neighbors == 3

if new_value != self.grid[row][cell]:
self.check_furthest(row, cell)

return new_value

Таким образом мы отделяем крайний обновления от решения новое значение ячейки. Он также может быть хорошей идеей, чтобы двигаться дальше обновление run_turn

    def check_cell(self, row, col):
"""Return whether the cell is dead or alive for the current
generation."""
if row < 0:
row = self.size - 1
if row > self.size - 1:
row = 0

if col < 0:
col = self.size - 1
if col > self.size - 1:
col = 0

return self.grid[row][col]

Использовать modulous вместо всех этих МФС

    def check_cell(self, row, col):
return self.grid[row % self.size][col % self.size]

В % делится с остатком, который дает конкретно обернуть вокруг объекта, который вы хотите.

    def count_living_neighbours(self, row, col):
"""Find how many neighnours of a given cell are alive."""
active_count = 0
to_check = [
(row - 1, col - 1), # Top left
(row - 1, col), # Top
(row - 1, col + 1), # Top right
(row, col - 1), # Left
(row, col + 1), # Right
(row + 1, col - 1), # Bottom left
(row + 1, col), # Bottom
(row + 1, col + 1) # Bottom Right
]

for crow, ccol in to_check:
if self.check_cell(crow, ccol):
active_count += 1

return active_count

Можно упростить функцию, заменив его:

        return sum(self.check_cell(row, col) for row, col in to_check)

Я рекомендую двигаться to_check к глобальной константы.

    def make_blank_grid(self):
"""Returns a blank grid for future use."""
grid = []
for row in range(0, self.size):
grid.append([])
for col in range(0, self.size):
grid[row].append([])
grid[row][col] = False
return grid

Написать ее следующим образом:

   def make_blank_grid(self):
"""Returns a blank grid for future use."""
grid = []
for row in range(0, self.size):
grid.append([False] * self.size)
return grid

Умножение создает новый список, который является оригинальной повторяются списка. Но использовать ее только на незыблемые ценности, как цифры и bools. Не используйте ничего, что может быть изменен, как и другие списки.

    def load_rle_into_grid(self, rle):
"""Loads a RLE representation of a playing field into the grid.

rle should be a file like object."""
reader = rlereader.GRLEReader()
data = reader.read_rle(rle) # Returns an uncompressed series of tokens from an rle file. The rle file is opened elsewhere than this package.

self.blank_grid()

current_token = 0

current_row = 0
current_col = 0
while True:
try:
token = data[current_token]
except IndexError:
break # Out of tokens

Использовать для маркера в данных вместо цикла while. Для петли почти всегда лучше, в то время как петли.

            if type(token) == rlereader.EOFToken:
break

Вырвавшись из-за или EOFToken или работает из маркеров странно. Вы должны, вероятно, иметь только разбить в случае или другой, не оба. Кроме того, проверять типы переменных не рекомендуется. Вы не должны делать это. Это rlereader ваш код или что-то еще?

            if token.value in ['b', 'o']: # 'o' = alive' 'b' = dead
self.grid[current_row][current_col] = (token.value == 'o')
current_col += 1
if current_col > self.size - 1:
print('Too wide an import, cancelling import.')
break

Когда что-то пойдет не так, его лучше бросить исключение, а не напечатать сообщение и продолжать свой веселый путь.

                if current_col >= self.furthest_col:
self.furthest_col = current_col + 2

Использовать Вы способ check_furthest, чтобы не дублировать логику.

            if token.value == '$': # $ indicates end of line.
current_row += 1
if current_row > self.size - 1:
print('Too high an import, cancelling import.')
break
current_col = 0
if current_row > self.furthest_row:
self.furthest_row = current_row + 2

current_token += 1

def randomise_grid(self):
"""Change every cell in a grid to random dead or alive state."""
for row in range(0, self.size):
for col in range(0, self.size):
self.grid[row][col] = random.choice([True, False])

self.furthest_row = self.size - 1
self.furthest_col = self.size - 1

def blank_grid(self):
"""Replace the current grid with a blank grid."""
self.grid = self.make_blank_grid()

Одна дополнительная вещь, чтобы рассмотреть будет использовать и NumPy. Библиотеки numpy-это библиотека Python, который обеспечивает многомерный массив типа. Его более естественно работать с списками списками. Он также обеспечивает векторных операций, которые позволяют выполнить ту же операцию в отношении всех элементов в массиве очень эффективно и с меньшим количеством кода.

4
ответ дан 7 мая 2011 в 08:05 Источник Поделиться