1

我正在尝试通过将 Cell 对象存储到一个集合中(必须使用类)来创建一个简单的生命游戏,但我遇到了我无法将单元对象添加到 Set 中的问题,因为它是不可散列的......有没有解决这个问题?谢谢!

class Cell():
    def __init__(self, row, col):
        self.row = row
        self.col = col
    def getRow(self):
        return self.row
    def getCol(self):
        return self.col
    def __eq__(self, other):
        if isinstance(other, self.__class__):
            return self.__dict__ == other.__dict__
        else:
            return False

    def __ne__(self, other):
        return not self.__eq__(other)    

class SparseLifeGrid(set):
    # Creates a new infinite-sized game grid with all cells set to dead.
    def __init__(self):
        self.rowList = []
        self.colList = []
        self.cellSet = set()

    def __add__(self, cell):
        self.cellSet.add(cell)
        self.rowList.append(cell.getRow())     
        self.colList.append(cell.getCol())     

    def minRange(self):
        #Returns a 2-tuple (minrow, mincol) that contains the minimum
        #row index and the minimum
        #column index that is currently occupied by a live cell.
        #None is returned if there are no alive cells.        
        return (sorted(self.rowList)[0], sorted(self.rowList)[0])

    def maxRange(self):
        #Returns a 2-tuple (maxrow, maxcol) that contains the
        #maximum row index and the maximum
        #column index that is currently occupied by a live cell.
        #None is returned if there are no live cells.        
        return (sorted(self.rowList,reverse = True)[0],\
                sorted(self.colList,reverse = True)[0])

    def clearCell(self, row, col):
        #Clears the individual cell (row, col) and sets it to dead.
        #If the cell is already dead, no action is taken.
        for item in self:
            if item == Cell(row,col):
                self.remove(item)

    def setCell(self, row, col):
        #Sets the indicated cell (row, col) to be alive.
        #If the cell is already alive, no action is taken.
        self.__add__(Cell(row,col))

    def isLiveCell(self, row, col):
        #Returns a boolean value indicating if the given
        #cell (row, col) contains a live organism.
        return Cell(row,col) in self

    def numLiveNeighbors(self, row, col):
    #checks how many live adjacents (not diagonals I think) a cell has
        surround = 0
        if self.isLiveCell(row+1,col):
            surround += 1
        if self.isLiveCell(row-1,col):
            surround += 1
        if self.isLiveCell(row, col+1):
            surround += 1
        if self.isLiveCell(row, col-1):
            surround += 1
        return surround

G = SparseLifeGrid()
G.setCell(2,3)
4

2 回答 2

0

你的对象是可变的,你还没有实现__hash__();但无论如何你都不想这样做。您的单元格仅在它们存在时表示活着,因此只需(row, col) 在您的集合中使用一个元组。由于元组是不可变且可散列的,因此您可以将它们放入您的集合中。

使用网格和游戏的类和对象,而不是单元格。

于 2012-10-25T22:32:09.690 回答
0

您需要使您的 Cell 实例不可变,然后创建一个__hash__始终保持不变的方法。如果您不能直接使用元组,这里有一个替代方案(仅从 中借用一点tuple):

class Cell:
    # each cell will have exactly two values, so no need for __dict__
    __slots__ = ["row", "col"]

    # set up values at construction time using super().__setitem__()
    def __init__(self, row, col):
        super().__setitem__("row", row)
        super().__setitem__("col", col)
        return self

    # a Cell is intended to be immutable, so __setattr__ always raises an error
    def __setattr__(self, name, value):
        if hasattr(self, name):
            raise AttributeError("{!r} object attribute {!r} is read-only"
                                 .format(self.__class__.__name__, name))
        else:
            raise AttributeError("{!r} object has no attribute {!r}"
                                 .format(self.__class__.__name__, name))

    # comparison operators
    def __eq__(self, other):
        return (isinstance(other, Cell) and
                self.row == other.row and
                self.col == other.col)

    def __ne__(self, other):
        return not self == other

    # hash function, with a value borrowed from a tuple
    def __hash__(self):
        return hash((self.row, self.col))

不过,这需要做很多工作,因为它相当于:

Cell = collections.namedtuple(["row", "col"])

您的网格类也有一些问题。例如,您正在覆盖__add__,它用于实现加法运算符,但您不返回任何内容,因此它不会像预期的那样工作。我怀疑您的意思是要覆盖该add方法(没有下划线)。但是,如果是这种情况,super().add()如果您希望网格实际作为一个集合运行,您将需要确保使用适当的参数进行调用。

此外,min(lst)应该比sorted(lst)[0](O(N) 而不是 O(N log N)) 快得多。

于 2012-10-26T13:59:23.623 回答