# HG changeset patch # User Laman # Date 2017-12-08 19:03:23 # Node ID 7f198428093622cac9b507f312bddd2bf81fe2a8 # Parent a98de30efa51f83e03dedb20c5d140caf3402152 Engine draft for exploring move sequences diff --git a/src/go/core.py b/src/go/core.py --- a/src/go/core.py +++ b/src/go/core.py @@ -101,10 +101,6 @@ def transitionMove(state1,state2): return False -def transitionSequence(state1,state2,diff,limit=0): - return [] - - def dfs(stack,board,mask): boardSize=len(board) (r,c)=stack[0] diff --git a/src/go/engine.py b/src/go/engine.py new file mode 100644 --- /dev/null +++ b/src/go/engine.py @@ -0,0 +1,59 @@ +import core + + +def transitionSequence(state1, state2, diff, limit=0): + return [] + + +class SpecGo(core.Go): + def __init__(self): + super().__init__() + self._diff=[] + + def load(self,state): + for (r,row) in enumerate(state): + for (c,x) in enumerate(row): + self.board[r][c]=x + + def listRelevantMoves(self,diff): + res=([],[]) + for d in diff: + (r,c,action,color)=d + colorKey=(1-color)<<1 + if action!="-": + res[colorKey].append((r,c)) + if action!="+": + self._helper.clear() + self._helper.floodFill(color,r,c) + res[colorKey].extend(self._helper.getLiberties()) + return res + + +class Engine: + def __init__(self): + self._g=SpecGo() + self._diff=[] + + def load(self,state1,diff): + self._g.load(state1) + self._diff=diff + + def iterativelyDeepen(self,state2): + for i in range(1,10): + seq=self.dfs(state2,i) + if seq: return seq + + def dfs(self,state2,limit): + g=self._g + for m in g.listRelevantMoves(): + g.doMove(m) + if g.board==state2: return m + if limit>1: + seq=self.dfs(state2,limit-1) + if seq: + seq.append(m) + return seq + g.undoMove(m) + return False + +eng=Engine() diff --git a/src/go/helperboard.py b/src/go/helperboard.py --- a/src/go/helperboard.py +++ b/src/go/helperboard.py @@ -39,6 +39,10 @@ class HelperBoard: for i in range(self._visitedCount): yield (self._visited[i*2],self._visited[i*2+1]) + def getLiberties(self): + for i in range(self._libCount): + yield (self._libs[i*2],self._libs[i*2+1]) + def clear(self): for i in range(self._visitedCount): (r,c)=(self._visited[i*2],self._visited[i*2+1]) diff --git a/src/statebag.py b/src/statebag.py --- a/src/statebag.py +++ b/src/statebag.py @@ -16,19 +16,29 @@ So we try to find the correct crossover - remember the better variant - linearize the fork back by discarding s'_j-s preceding the crossover and s_j-s following the crossover """ +import random from util import EMPTY -from go.core import transitionSequence +from go.engine import transitionSequence + +rand=random.Random() +rand.seed(361) +zobristNums=tuple( + tuple( + tuple(rand.getrandbits(32) for i in range(3)) for c in range(19) + ) for r in range(19) +) ## Crude lower bound on edit distance between states. def estimateDistance(diff): + # lot of room for improvements additions=sum(1 for d in diff if d[2]=="+") deletions=sum(1 for d in diff if d[2]=="-") replacements=len(diff)-additions-deletions if additions>0: return additions+replacements elif replacements==0 and deletions>0: return 2 # take n, return 1 - return replacements # ??? + return replacements+1 # ??? class BoardState: @@ -40,6 +50,13 @@ class BoardState: self.weight=0 self.diff2Prev=None + def hash(self): + res=0 + for (r,row) in enumerate(self._board): + for (c,item) in enumerate(row): + res^=zobristNums[r][c][item+1] + return res + def __iter__(self): return iter(self._board) def __getitem__(self,key): return self._board[key] @@ -52,9 +69,13 @@ class BoardState: if item1==item2: continue elif item2==EMPTY: res.append((r,c,"+",item1)) elif item1==EMPTY: res.append((r,c,"-",item2)) - else: res.append((r,c,item2,item1)) # from->to + else: res.append((r,c,"*",item1)) # ->to return res + def __eq__(self,x): + # might want to use hash + return self._board==x._board + class StateBag: def __init__(self): @@ -62,6 +83,8 @@ class StateBag: def pushState(self,board): sn=BoardState(board) + if self._states and sn==self._states[-1]: return # no change + for s in reversed(self._states): diff=sn-s distEst=estimateDistance(diff)