python数据结构学习笔记-2016-10-15-02-生命游戏

        2.5 生命游戏

        生命游戏由英国数学及John H.Conway设计,是一个零人游戏。

        2.5.1 游戏规则

        这个游戏使用一张无限大的直角坐标网格,每一个网格可以由一个细胞占据,当一个网格被细胞占据,称为活的(alive),而空网格被称为死的(dead),也可以以活细胞和死细胞称呼。

        游戏的每一轮称为一代(generation),根据每个网格细胞的当前形态(configuration),决定下一代中网格细胞的形态。

  1.  当一个网格细胞是活的,并且周围有2~3个邻居(活细胞)时,其在下一代中是活的,注意周围是指水平、竖直和对角线相邻的网格;
  2.  当一个网格细胞是活的,并且周围有0~1个邻居时,其在下一代中变成死的;
  3.  当一个网格细胞是活的,并且周围有4~5个邻居时,其在下一代中变成死的;
  4.  当一个网格细胞是死的,并且周围有3个邻居时,其在下一代中变成活的,其余所有死细胞在下一代中,仍是死的。
        这一游戏的最终结果依据于初始状态和世代数,大部分结果是所有细胞都会死去,但也有一些有趣的情况。

        稳态:

         两相振荡:


         

       2.5.2 设计一个解决方法

       本游戏需要创建一个生命网格ADT,来记录每一代的网格细胞的状态。这一ADT,应包含如下方法:

  • LifeGrid(nrows, ncols):创建生命网格实例,行数是nrows,列数是ncols,所有网格被初始化为死的状态;
  • numRows():返回行数;
  • numCols():返回列数;
  • configure(coordList):设定本世代中网格细胞的状态,将一系列给定坐标的网格设定为活细胞状态,而coordList是由多个含两个数值的元组组成,其余网格为死细胞状态;
  • clearCell(row, col):将给定坐标的网格细胞设定为死细胞;
  • setCell(row, col):将给定坐标的网格细胞设定为活细胞;
  • isLiveCell(row, col):判断给定坐标的网格细胞的状态,False为死细胞,True为活细胞;
  • numLiveNeighbors(row, col):计算给定坐标周围活细胞数,特殊情况是考虑在网格边缘处周围活细胞数统计。
#-*-coding: utf-8-*-

# 生命游戏程序

from life import LifeGrid

# 网格大小
GRID_WIDTH = int(raw_input("Please enter a positive integer as width: "))
GRID_HEIGHT = int(raw_input("Please enter a positive integer as height: "))

# 初始状态
INIT_CONFIG = [(0, 0), (0, 1), (1, 0), (1, 2), (3, 2), (3, 4), (5, 4), (5, 6), (7, 6), (7, 8), (9, 8), (9, 10), (11, 10), (11, 12), (12, 11), (12, 12)]

# 世代数
NUM_GENS = int(raw_input("Please enter a positive integer as generation: "))

# 产生下一代的生命
def evolve(grid):
    # 储存下一代活细胞的列表
    liveCells = list()
    
    # 遍历整个网格
    for i in range(grid.numRows()):
        for j in range(grid.numCols()):
            # 读取周围活细胞数
            neighbors = grid.numLiveNeighbors(i, j)

            # 如果该坐标有活细胞,并且周围活细胞数是2或3,将该坐标加入到下一代活细胞的列表
            if (neighbors == 2 and grid.isLiveCell(i, j)) or (neighbors == 3):
                liveCells.append((i, j))

    # 使用下一代活细胞的列表去初始化网格
    grid.configure(liveCells)

# 打印一个基于文本表示的生命游戏
def draw(grid):
    for i in range(grid.numRows()):
        string = ''
        for j in range(grid.numCols()):
            if grid.isLiveCell(i, j):
                string += '@  '
            else:
                string += '.  '
        print string
    print '\n'

def main():
    # 构建游戏网格,并初始化
    grid = LifeGrid(GRID_WIDTH, GRID_HEIGHT)
    grid.configure(INIT_CONFIG)

    # 游戏开始
    draw(grid)
    # for i in INIT_CONFIG:
        # print grid.numLiveNeighbors(*i)
    for i in range(NUM_GENS):
        evolve(grid)
        draw(grid)

if __name__ == "__main__":
    main()
       draw()函数是打印当前网格状态,而evolve()是产生下一代的网格状态。


         2.5.3 实现
#-*-coding: utf-8-*-

# 实现LifeGrid ADT

from myarray2d import Array2D

class LifeGrid(object):
    # 定义代表细胞状态的常量
    DEAD_CELL = 0
    LIVE_CELL = 1

    # 创建游戏网格实例,并将所有细胞设定为死细胞状态
    def __init__(self, numRows, numCols):
        # 创建网格实例
        self._grid = Array2D(numRows, numCols)
        # 将所有细胞设定为死细胞状态
        self.configure(list())

    def numRows(self):
        return self._grid.numRows()

    def numCols(self):
        return self._grid.numCols()

    # 将给定网格坐标的细胞设为活细胞,网格坐标由列表传入
    def configure(self, coordList):
        # 先将所有网格中的细胞设为死细胞
        for i in range(self.numRows()):
            for j in range(self.numCols()):
                self.clearCell(i, j)

        # 再将给定网格坐标的细胞设为活细胞
        for coord in coordList:
            self.setCell(coord[0], coord[1])

    # 判断给定网格坐标中的细胞状态
    def isLiveCell(self, row, col):
        return self._grid[row, col] == LifeGrid.LIVE_CELL

    def clearCell(self, row, col):
        self._grid[row, col] = LifeGrid.DEAD_CELL

    def setCell(self, row, col):
        self._grid[row, col] = LifeGrid.LIVE_CELL

    # 计算给定网格周围活细胞数
    def numLiveNeighbors(self, row, col):
        count = -1 if self.isLiveCell(row, col) else 0
        for r in range(row-1, row+2):
            for c in range(col-1, col+2):
                try:
                    if self.isLiveCell(r, c):
                        count += 1
                except AssertionError, e:
                    continue
        return count





        

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值