首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Python -生命游戏

Python -生命游戏
EN

Code Review用户
提问于 2013-09-25 20:12:16
回答 2查看 3.7K关注 0票数 4

以下是我在Python中实现的John的“生命游戏”:

代码语言:javascript
复制
from copy import deepcopy

def countSurrounding(board, row, cell):
    SURROUNDING = ((row - 1, cell - 1),
                   (row - 1, cell    ),
                   (row - 1, cell + 1),
                   (row    , cell - 1),
                   (row    , cell + 1),
                   (row + 1, cell - 1),
                   (row + 1, cell    ),
                   (row + 1, cell + 1))
    count = 0
    for row, cell in SURROUNDING:
        if isInRange(board, row, cell) and board[row][cell] == True:
            count += 1
    return count

def isInRange(board, row, cell):
    return 0 <= row < len(board) and 0 <= cell < len(board[0])

def nextGeneration(board):
    nextBoard = deepcopy(board)
    for row in range(len(board)):
        for cell in range(len(board[0])):
            if board[row][cell] == True and countSurrounding(board, row, cell) not in (2, 3):
                nextBoard[row][cell] = False
            elif board[row][cell] == False and countSurrounding(board, row, cell) == 3:
                nextBoard[row][cell] = True
    return nextBoard

def printBoard(board):
    for row in board:
        for cell in row:
            if cell == True:
                print("#", end = "")
            else:
                print(".", end = "")
        print()
    print()

def main():
    board = [[False, False, False, False, False, False, False, False, False],
             [False, False, False, True , False, False, False, False, False],
             [False, True , False, True , False, False, False, False, False],
             [False, False, True , True , False, False, False, False, False],
             [False, False, False, False, False, False, False, False, False],
             [False, False, False, False, False, False, False, False, False],
             [False, False, False, False, False, False, False, False, False],
             [False, False, False, False, False, False, False, False, False],
             [False, False, False, False, False, False, False, False, False]]
    for i in range(10):
        printBoard(board)
        board = nextGeneration(board)

main()

有人能建议对我的代码进行优化吗?

谢谢

EN

回答 2

Code Review用户

发布于 2013-09-28 20:53:56

1.对代码

的注释

  1. 你在打给main()的电话上没有警卫。这使得使用交互式解释器调试程序变得更加困难:一旦模块被导入,它就调用main()并开始运行。最好派个警卫:if __name__ == '__main__':main()
  2. 这个程序由持久化状态(板)和对该状态的一组操作组成。因此,它迫切需要以类的形式实现。有关如何做到这一点,请参见第3节。
  3. 观察在终端上运行的元胞自动机的进展是非常乏味的。这是一种真正需要使用像PyGame这样的图形工具箱来绘制和动画的程序。有关如何做到这一点,请参见第4节。
  4. 几乎没有必要显式地将值与TrueFalse进行比较。代替: if单元格==真:您可以写: if单元格:和代替: if board == False:您可以写:如果不是板
  5. 像这样的巨大的价值块很难输入,也很难检查。板= [假,假,假,真,假,假,假,假,假,假,真,假,假,假,假,假,假,假,假,假,假,假]最好画一幅“图片”,并编写一些代码,将其解码为您想要的值:滑动器=‘’.‘o.o ..oo’参见下面第3节中的paste方法,以了解如何解码这种图片。

2.建议

  1. 当你有这样一个程序操作一个二维的单元格数组时,如果你把二维数组表示为一个一维列表,它通常会简化一些事情。然后,一个单元格可以用单个数字而不是一对来表示;查找的形式是array[cell]而不是array[x][y],相邻的单元可以通过简单的算术操作找到。
  2. 这是生命游戏的一个特点,在大多数情况下,几乎没有细胞在改变。您可以利用这一事实来加快更新操作。与其检查所有单元格是否需要更新,不如维护一组需要查看的单元格。每当你改变一个细胞从活到死,反之亦然,添加它,以及它的所有邻居,到集合。在更新操作中,只查看在上一次更新操作过程中添加到集中的单元格。这意味着您不必复制整个世界,每个更新:您只需要一个副本的信息(活性和邻居计数)有关的细胞在集合。
  3. 类似地,每次更新单元格时,您都可以保持一个包含这些邻居计数的数组,并在单元格发生更改时更新该数组,而不是每次更新活邻居的数量。

3.订正代码

代码语言:javascript
复制
from itertools import product

class Life(object):
    def __init__(self, width, height):
        self.width = width
        self.height = height
        cells = (width + 2) * (height + 2)
        self.live = [False] * cells
        self.in_bounds = [True] * cells
        self.neighbours = [0] * cells
        for i in range(width + 2):
            self.in_bounds[i] = self.in_bounds[-i] = False
        for j in range(height):
            k = (j + 1) * (width + 2)
            self.in_bounds[k - 1] = self.in_bounds[k] = False
        self.neighbourhood = [y * (width + 2) + x
                              for x, y in product((-1, 0, 1), repeat=2)
                              if x or y]
        self.needs_update = set()

    def cell(self, x, y):
        """Return the cell number corresponding to the coordinates (x, y)."""
        return (self.width + 2) * (y + 1) + x + 1

    def set(self, p, value):
        """Set cell number 'p' to 'value' (True=live, False=dead)."""
        if value != self.live[p] and self.in_bounds[p]:
            self.live[p] = value
            self.needs_update.add(p)
            adjust = 1 if value else -1
            for n in self.neighbourhood:
                n += p
                if self.in_bounds[n]:
                    self.neighbours[n] += adjust
                    self.needs_update.add(n)

    def update(self, steps=1):
        """Update the world by 'steps' generations (default: 1)."""
        for _ in range(steps):
            u = [(p, self.live[p], self.neighbours[p]) for p in self.needs_update]
            self.needs_update = set()
            for p, live, neighbours in u:
                if live and not 2 <= neighbours <= 3:
                    self.set(p, False)
                elif not live and neighbours == 3:
                    self.set(p, True)

    def paste(self, s, x, y):
        """Decode 's' as a life pattern (o = live, any other character = dead)
        and paste it with top left corner at (x, y).

        """
        for j, line in enumerate(s.strip().splitlines()):
            for i, char in enumerate(line.strip()):
                self.set(self.cell(x + i, y + j), char == 'o')

注意:

  1. 可以将livein_boundsneighbours数组组合为一个,也许可以使用位旋转来组合值(邻居计数适合4位,而其他两个数组各为1位)。为了简单起见,我把它放在三个单独的数组中。

4.动画

下面是派克中的一个快速实现:

代码语言:javascript
复制
import pygame
from pygame.constants import KEYUP, MOUSEBUTTONDOWN, MOUSEMOTION, QUIT, \
                             K_p, K_q, K_s, K_ESCAPE, K_SPACE

class PygameLife(Life):
    def __init__(self, width, height,
                 background=pygame.Color(240, 240, 255),
                 foreground=pygame.Color('black'),
                 cell_size=4):
        super(PygameLife, self).__init__(width, height)
        self.background = background
        self.foreground = foreground
        self.cell_size = cell_size

    def draw(self):
        screen = pygame.display.get_surface()
        screen.fill(self.background)
        c = self.cell_size
        for x in range(self.width):
            for y in range(self.height):
                if self.live[self.cell(x, y)]:
                    screen.fill(self.foreground, pygame.Rect(x * c, y * c, c, c))
        pygame.display.flip()

    def screen_cell(self, pos):
        """Return the cell number corresponding to screen position 'pos', or
        None if the position is out of bounds.

        """
        x, y = pos
        x //= self.cell_size
        y //= self.cell_size
        if 0 <= x < self.width and 0 <= y < self.height:
            return self.cell(x, y)
        return None

    def run(self):
        pygame.init()
        pygame.display.set_mode((self.width * self.cell_size,
                                 self.height * self.cell_size))
        paused = False
        drawing = False
        running = True
        while running:
            for event in pygame.event.get():
                t = event.type
                if t == QUIT or t == KEYUP and event.key in (K_q, K_ESCAPE):
                    running = False
                elif t == KEYUP and event.key in (K_p, K_SPACE):
                    paused = not paused
                elif t == KEYUP and event.key in (K_s,):
                    self.update()
                elif t == MOUSEBUTTONDOWN and event.button == 1:
                    paused = True
                    p = self.screen_cell(event.pos)
                    drawing = not self.live[p]
                    self.set(p, drawing)
                elif t == MOUSEMOTION and event.buttons[0]:
                    paused = True
                    self.set(self.screen_cell(event.pos), drawing)
            if paused:
                pygame.display.set_caption('Paused (press SPACE to run)')
            else:
                pygame.display.set_caption('Life')
                self.update()
            self.draw()
        pygame.quit()

下面是行动中的比尔·高斯珀 滑翔机炮

代码语言:javascript
复制
>>> glider_gun = '''
........................o...........
......................o.o...........
............oo......oo............oo
...........o...o....oo............oo
oo........o.....o...oo..............
oo........o...o.oo....o.o...........
..........o.....o.......o...........
...........o...o....................
............oo......................'''
>>> p = PygameLife(100, 60)
>>> p.paste(glider_gun, 8, 1)
>>> p.run()

5.高级主题

典型的生活模式包含许多重复的对象。例如,滑翔机炮的输出包含许多滑翔机,它们的行为都是相同的。如果能够利用这种重复,只计算一次滑翔机(或任何其他重复模式)的演变,结果就会出现在世界上所有必要的地方,那就太好了。

使这一想法精确,并将其转化为一种算法,将导致比尔·高斯珀的哈希姆

票数 5
EN

Code Review用户

发布于 2013-09-25 22:22:16

先读http://www.python.org/dev/peps/pep-0008/,然后读毕达顿。您会惊讶于您的代码将如何得到改进,将新代码作为一个新文件编写并进行比较。

在你的董事会名单上,这是一块巨大的假嘘声砖。通过使用列表理解,您可以轻松、干净地填充此列表。

票数 2
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/31817

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档