# HG changeset patch # User Laman # Date 2017-12-13 13:41:29 # Node ID 0cb3fbe06b5d87fe5a12a98a4d41f76f908311b3 # Parent 077600f0c5f8d5b1211adc632a8733fc8de98c02 Go, Engine: some tests and numerous bugfixes diff --git a/src/go/core.py b/src/go/core.py --- a/src/go/core.py +++ b/src/go/core.py @@ -35,7 +35,7 @@ class Go: self._helper.clear() if not self._helper.floodFill(-color,row+r,col+c,EMPTY): self._remove() - # check for suicide + # check for suicide and prevent it self._helper.clear() if not self._helper.floodFill(color,row,col,EMPTY): self.board[row][col]=EMPTY @@ -46,7 +46,7 @@ class Go: return True def undoMove(self,r,c,captures): - assert self.board[r][c]==-1*self.toMove + 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: @@ -62,6 +62,11 @@ class Go: (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) diff --git a/src/go/engine.py b/src/go/engine.py --- a/src/go/engine.py +++ b/src/go/engine.py @@ -10,22 +10,17 @@ class SpecGo(core.Go): def __init__(self,boardSize=19): super().__init__(boardSize) - 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): """There can be 3 different changes in the diff: additions, deletions and replacements. Additions can be taken as relevant right away. Deletions and replacements had to be captured, so we add their liberties. Also any non-missing stones of partially deleted (or replaced) groups had to be replayed, so add them too. - Needs to handle: Take n, return 1. Snapback. + Needs to handle snapback. There's no end to what could be theoretically relevant, but such sequences are long and we will pretend they won't happen.""" res=(set(),set()) for d in diff: (r,c,action,color)=d - colorKey=(1-color)<<1 # {-1,1}->{1,0} + colorKey=(1-color)>>1 # {-1,1}->{1,0} if action!="-" and (r,c) not in res[colorKey]: res[colorKey].add((r,c)) # this is rather sloppy but correct. the time will show if it is effective enough @@ -39,13 +34,13 @@ class SpecGo(core.Go): if ri>0: res[colorKey].add((ri-1,ci)) res[1-colorKey].add((ri-1,ci)) - if ri0: res[colorKey].add((ri,ci-1)) res[1-colorKey].add((ri,ci-1)) - if ci>1]: + for (r,c) in self._moveList[(1-g.toMove)>>1]: if g.board[r][c]!=EMPTY: continue neighbours=( g.board[r-1][c] if r>0 else None, - g.board[r+1][c] if r0 else None, - g.board[r][c+1] if c1: + toMove=-1*g.toMove seq=self.dfs(state2,limit-1) if seq: - seq.append((-1*g.toMove,r,c)) + seq.append((toMove,r,c)) return seq g.undoMove(r,c,captured) return False diff --git a/src/go/helperboard.py b/src/go/helperboard.py --- a/src/go/helperboard.py +++ b/src/go/helperboard.py @@ -49,6 +49,6 @@ class HelperBoard: self._board[r][c]=EMPTY self._visitedCount=0 for i in range(self._libCount): - (r,c)=(self._libs[i*2],self._visited[i*2+1]) + (r,c)=(self._libs[i*2],self._libs[i*2+1]) self._board[r][c]=EMPTY self._libCount=0 diff --git a/src/tests/testEngine.py b/src/tests/testEngine.py --- a/src/tests/testEngine.py +++ b/src/tests/testEngine.py @@ -20,3 +20,36 @@ class TestTransitions(TestCase): eng=Engine(g) eng.load(s1,s2-s1) self.assertEqual(eng.dfs(s2,1),[(1,1,1)]) + + def testCapture(self): + s1=BoardState([ + [0,-1,0], + [-1,1,0], + [0,-1,0] + ]) + s2=BoardState([ + [0,-1,0], + [-1,0,-1], + [0,-1,0] + ]) + g=SpecGo(3) + g.toMove=-1 + eng=Engine(g) + eng.load(s1,s2-s1) + self.assertEqual(eng.dfs(s2,1),[(-1,1,2)]) + + def testMulti(self): + s1=BoardState([ + [0,0,0], + [0,0,0], + [0,0,0] + ]) + s2=BoardState([ + [0,0,0], + [0,1,-1], + [0,0,0] + ]) + g=SpecGo(3) + eng=Engine(g) + eng.load(s1,s2-s1) + self.assertEqual(eng.dfs(s2,2),[(-1,1,2),(1,1,1)]) diff --git a/src/tests/testGo.py b/src/tests/testGo.py --- a/src/tests/testGo.py +++ b/src/tests/testGo.py @@ -1,6 +1,6 @@ from unittest import TestCase -from go.core import isLegalPosition +from go.core import isLegalPosition, Go class TestLegal(TestCase): @@ -23,3 +23,25 @@ class TestLegal(TestCase): [0,0,0,0,0] ] self.assertFalse(isLegalPosition(board)) + + +class TestMove(TestCase): + def testCapture(self): + g=Go(3) + g.load([ + [0,1,0], + [1,-1,0], + [0,1,0] + ]) + g.toMove=1 + g.doMove(1,1,2) + self.assertEqual(g.board,[ + [0,1,0], + [1,0,1], + [0,1,0] + ]) + + g._helper.clear() + for row in g._helper._board: + for x in row: + self.assertEqual(x,0) diff --git a/src/tests/testHelper.py b/src/tests/testHelper.py new file mode 100644 --- /dev/null +++ b/src/tests/testHelper.py @@ -0,0 +1,16 @@ +from unittest import TestCase + +from go.helperboard import HelperBoard + + +class TestFlood(TestCase): + def testCapture(self): + b=[ + [0,1,0], + [1,-1,1], + [0,1,0] + ] + h=HelperBoard(b) + self.assertEqual(h.floodFill(-1,1,1,0), False) + captured=set(h.getContinuousArea()) + self.assertEqual(captured, {(1,1)})