# HG changeset patch # User Laman # Date 2017-04-17 20:28:13 # Node ID 2fcaffe8cb708aba3d370157caebea66b7c7421d # Parent 0d57edb8be11235ce0f3fa1662bb6e028ee90316 checking for a legal position diff --git a/src/core.py b/src/core.py --- a/src/core.py +++ b/src/core.py @@ -6,7 +6,7 @@ import PIL from util import MsgQueue from gui import gui from imageanalyzer import ImageAnalyzer -from go import Go +from go import Go, isLegalPosition import config as cfg @@ -47,7 +47,10 @@ class Core: def analyze(self): if self.detector.analyze(self._frame): - self._guiMessages.send("setGameState",(self.detector.board,)) + if isLegalPosition(self.detector.board): + self._guiMessages.send("setGameState",(self.detector.board,)) + else: + log.info("illegal position detected") def listen(self): listenerThread=threading.Thread(target=lambda: self._ownMessages.listen()) diff --git a/src/go.py b/src/go.py --- a/src/go.py +++ b/src/go.py @@ -1,4 +1,4 @@ -EMPTY=0 +EMPTY=0 BLACK=1 WHITE=-1 @@ -7,7 +7,8 @@ class Go: ## Initializes self.board to a list[r][c]=EMPTY. def __init__(self,boardSize=19): self.boardSize=boardSize - self.board=[[EMPTY]*self.boardSize for x in range(boardSize)] + self.board=[[EMPTY]*boardSize for x in range(boardSize)] + self._temp=[[EMPTY]*boardSize for x in range(boardSize)] ## Executes a move. # @@ -22,11 +23,11 @@ class Go: # capture neighbors for r,c in ((-1,0),(1,0),(0,-1),(0,1)): - self.temp=[[False]*self.boardSize for x in self.board] + self._clearTemp() if not self._floodFill(-color,row+r,col+c): self._remove() # check for suicide - self.temp=[[False]*self.boardSize for x in self.board] + self._clearTemp() if not self._floodFill(color,row,col): self.board[row][col]=EMPTY return False @@ -39,19 +40,52 @@ class Go: # @return True if alive, False if captured def _floodFill(self,color,row,col): if col<0 or col>=self.boardSize or row<0 or row>=self.boardSize: return False # out of range - if self.temp[row][col]: return False # already visited + if self._temp[row][col]: return False # already visited if self.board[row][col]==EMPTY: return True # found a liberty if self.board[row][col]!=color: return False # opponent's stone - self.temp[row][col]=True # set visited + self._temp[row][col]=True # set visited return self._floodFill(color,row,col-1) or self._floodFill(color,row,col+1) or self._floodFill(color,row-1,col) or self._floodFill(color,row+1,col) # check neighbors ## Removes stones at coordinates marked with True in self.temp. def _remove(self): for r in range(self.boardSize): for c in range(self.boardSize): - if self.temp[r][c]: self.board[r][c]=EMPTY + if self._temp[r][c]: self.board[r][c]=EMPTY + def _clearTemp(self): + for i in range(self.boardSize): + for j in range(self.boardSize): + self._temp[i][j]=EMPTY def exportBoard(board): substitutions={EMPTY:".", BLACK:"X", WHITE:"O"} return "\n".join("".join(substitutions.get(x,"?") for x in row) for row in board) + + +def isLegalPosition(board): + boardSize=len(board) + temp=[[None]*boardSize for x in range(boardSize)] + + for r in range(boardSize): + for c in range(boardSize): + if board[r][c]==EMPTY: continue + if temp[r][c]: continue + if not dfs([(r,c)],board,temp): return False + return True + + +def dfs(stack,board,mask): + boardSize=len(board) + (r,c)=stack[0] + color=board[r][c] + + while len(stack)>0: + (r,c)=stack.pop() + if board[r][c]==EMPTY: return True + elif board[r][c]!=color: continue + elif mask[r][c]: return True + mask[r][c]=True + for (x,y) in ((0,-1),(-1,0),(0,1),(1,0)): + if 0<=r+y