import logging as log from util import EMPTY,BLACK,WHITE, colorNames,hashBoard from .helperboard import HelperBoard from .gamerecord import GameRecord class Go: ## Initializes self.board to a list[r][c]=EMPTY. def __init__(self,boardSize=19): self.boardSize=boardSize self.board=[[EMPTY]*boardSize for x in range(boardSize)] self.toMove=BLACK self._helper=HelperBoard(self.board) self._hashes=[] self._record=GameRecord() def listMoves(self,diff=[]): return [] ## Executes a move. # # Doesn't check for kos. Suicide not allowed. # # @param color BLACK or WHITE # @return True on success, False on failure (illegal move) def doMove(self,color,row,col): if color!=self.toMove: log.warning("move by %s out of order",colorNames[color]) if self.board[row][col]!=EMPTY: return False self.board[row][col]=color # capture neighbors for r,c in ((-1,0),(1,0),(0,-1),(0,1)): self._helper.clear() if not self._helper.floodFill(-color,row+r,col+c,EMPTY): self._remove() # check for suicide and prevent it self._helper.clear() if not self._helper.floodFill(color,row,col,EMPTY): self.board[row][col]=EMPTY return False self._record.move(color,row,col) self.toMove=-1*color self._hashes.append(self.hash()) return True def undoMove(self,r,c,captures): assert self.board[r][c]==-1*self.toMove, "{0}!={1}".format(self.board[r][c],-1*self.toMove) self.toMove*=-1 self.board[r][c]=self.toMove if len(captures)>0: self._helper.clear() for (r,c) in captures: self._helper.floodFill(EMPTY,r,c) self._fill(-self.toMove) self._hashes.pop() def transitionMove(self,board): res=transitionMove(self.board,board) if not res: return res (r,c,color)=res return self.doMove(color,r,c) def load(self,board): for (r,row) in enumerate(board): for (c,x) in enumerate(row): self.board[r][c]=x def hash(self): return hashBoard(self.board) ## Removes stones at coordinates marked with True in self.helper. def _remove(self): self._fill(EMPTY) def _fill(self,filling): for (r,c) in self._helper.getContinuousArea(): self.board[r][c]=filling 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 transitionMove(state1,state2): moves=[] for (r,(row1,row2)) in enumerate(zip(state1,state2)): for (c,(item1,item2)) in enumerate(zip(row1,row2)): if item1==EMPTY and item2!=EMPTY: moves.append((r,c,item2)) if len(moves)==0: log.info("no new stone") return None elif len(moves)==1: log.info("new stone: %s",moves[0]) return moves[0] else: log.warning("too many new stones: %s",moves) return False 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