diff --git a/src/benchmark.py b/src/benchmark.py new file mode 100644 --- /dev/null +++ b/src/benchmark.py @@ -0,0 +1,10 @@ +import cProfile + +from tests.testEngine import TestTransitions + + +t=TestTransitions() + +cProfile.run(r""" +t.testReal() +""") diff --git a/src/go/core.py b/src/go/core.py --- a/src/go/core.py +++ b/src/go/core.py @@ -1,6 +1,6 @@ import logging as log -from util import EMPTY,BLACK,WHITE, colorNames,hashBoard +from util import EMPTY,BLACK,WHITE, colorNames,hashBoard,diffHash from .helperboard import HelperBoard from .gamerecord import GameRecord @@ -12,7 +12,8 @@ class Go: self.board=[[EMPTY]*boardSize for x in range(boardSize)] self.toMove=BLACK self._helper=HelperBoard(self.board) - self._hashes=[] + self._freshHash=hashBoard(self.board) # always reflecting current state of the board + self._hashes=[self._freshHash] self._record=GameRecord() ## Executes a move. @@ -21,25 +22,27 @@ class Go: # # @param color BLACK or WHITE # @return True on success, False on failure (illegal move) - def doMove(self,color,row,col): + def doMove(self,color,r,c): if color!=self.toMove: log.warning("move by %s out of order",colorNames[color]) - if self.board[row][col]!=EMPTY: return False + if self.board[r][c]!=EMPTY: return False - self.board[row][col]=color + self.board[r][c]=color + self._freshHash^=diffHash(r,c,EMPTY,color) # capture neighbors - for r,c in ((-1,0),(1,0),(0,-1),(0,1)): + for dr,dc 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() + if not self._helper.floodFill(-color,r+dr,c+dc,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 + if not self._helper.floodFill(color,r,c,EMPTY): + self.board[r][c]=EMPTY + self._freshHash=self._hashes[-1] return False - self._record.move(color,row,col) + self._record.move(color,r,c) self.toMove=-1*color - self._hashes.append(self.hash()) + self._hashes.append(self._freshHash) return True def undoMove(self,r,c,captures): @@ -54,6 +57,7 @@ class Go: self.board[r][c]=EMPTY self.toMove*=-1 self._hashes.pop() + self._freshHash=self._hashes[-1] def transitionMove(self,board): res=transitionMove(self.board,board) @@ -65,9 +69,11 @@ class Go: for (r,row) in enumerate(board): for (c,x) in enumerate(row): self.board[r][c]=x + self._freshHash=hashBoard(self.board) + self._hashes=[self._freshHash] def hash(self): - return hashBoard(self.board) + return self._hashes[-1] ## Removes stones at coordinates marked with True in self.helper. def _remove(self): @@ -75,6 +81,7 @@ class Go: def _fill(self,filling): for (r,c) in self._helper.getContinuousArea(): + self._freshHash^=diffHash(r,c,self.board[r][c],filling) self.board[r][c]=filling diff --git a/src/statebag.py b/src/statebag.py --- a/src/statebag.py +++ b/src/statebag.py @@ -39,9 +39,11 @@ class BoardState: self.moves=[] self.weight=0 self.diff2Prev=None + self._hash=None def hash(self): - return hashBoard(self._board) + if self._hash is None: self._hash=hashBoard(self._board) + return self._hash def export(self): return exportBoard(self._board) diff --git a/src/util.py b/src/util.py --- a/src/util.py +++ b/src/util.py @@ -52,6 +52,9 @@ def hashBoard(board): res^=zobristNums[r][c][item+1] return res +def diffHash(r,c,oldItem,newItem): + h=zobristNums[r][c] + return h[oldItem+1] ^ h[newItem+1] def exportBoard(board): substitutions={EMPTY:".", BLACK:"X", WHITE:"O"}