2012-10-25 2 views
1

나는 (클래스를 사용해야하는) 셀 객체를 저장하여 간단한 게임을 만들려고 노력하고 있는데, 그 이유는 세트에 셀 객체를 추가 할 수없는 문제에 봉착했습니다 unhashable입니다 ...이 주위에 어떤 방법이 있습니까? 감사!게임 LIFE 해싱 파이썬

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

[게터를 만든 이유는 무엇입니까?] (http://archive.org/details/SeanKellyRecoveryfromAddiction) –

답변

0

Cell 인스턴스를 불변으로 만들어야하고 항상 동일하게 유지되는 __hash__ 메서드를 만들어야합니다. 이것은 많은 일이 뭔가를하지만 오히려

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"]) 
직접 튜플을 사용할 수없는 경우, 여기에 대안 (즉 tuple에서만 조금 빌려가)입니다

그리드 클래스에는 몇 가지 문제가 있습니다. 예를 들어, 더하기 연산자를 구현하는 데 사용되는 __add__을 재정의하지만 아무 것도 반환하지 않으므로 예상 한 것처럼 작동하지 않습니다. 대신 add 메서드 (밑줄 없음)를 무시하는 것이 좋습니다. 그러나 그럴 경우 그리드를 실제로 세트로 사용하려면 super().add()에 적절한 인수를 지정해야합니다.

또한 min(lst)sorted(lst)[0] (O (N 로그 N) 대신 O (N))보다 훨씬 빠릅니다.

0

개체가 변경 가능하며 사용자가 __hash__()을 구현하지 않았습니다. 하지만 어쨌든 그렇게하고 싶지는 않습니다. 귀하의 세포는 존재하는 경우에만 살아 있다는 것을 나타낼 수 있으므로 집합에 튜플 (row, col)을 사용하십시오. 튜플은 불변이고 해시 가능하기 때문에, 당신은 그것들을 당신의 세트에 넣을 수 있습니다.

세포가 아닌 그리드와 게임의 클래스와 객체를 사용하십시오.

+0

빠른 대답 주셔서 감사합니다. 그러나 셀 집합으로 튜플을 사용할 수 없습니다. – user1775641

+0

'class Cell (tuple) : pass' ...;) 또는 아마도 명명 된 튜플을 유혹했다. 그러나 실제로, 튜플은 다른 어떤 객체와 같은 객체입니다. – retracile