Files
@ 7cb01d4080c9
Branch filter:
Location: OneEye/src/go/core.py
7cb01d4080c9
3.9 KiB
text/x-python
a hinted neural network (failed)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 | import logging
from util import EMPTY,BLACK,WHITE, colorNames,hashBoard,diffHash
from .helperboard import HelperBoard
from .gamerecord import GameRecord
log=logging.getLogger(__name__)
PASS=(99,99)
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
# utility field to allow undoing moves. but only useful right after doMove. this class doesn't need it, so it is not kept correct at other times
self.captures=[None]*4
self.captureCount=0
self._helper=HelperBoard(self.board)
self._freshHash=hashBoard(self.board) # always reflecting current state of the board
self._hashes=[self._freshHash]
self._record=GameRecord()
## 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,r,c):
if color!=self.toMove: log.warning("move by %s out of order",colorNames[color])
if (r,c)==PASS:
self.toMove*=-1 # pass
self._hashes.append(self._freshHash)
return True
if self.board[r][c]!=EMPTY: return False
self.board[r][c]=color
self._freshHash^=diffHash(r,c,EMPTY,color)
# capture neighbors
self.captureCount=0
for dr,dc in ((-1,0),(1,0),(0,-1),(0,1)):
self._helper.clear()
if not self._helper.floodFill(-color,r+dr,c+dc,EMPTY):
self.captures[self.captureCount]=(r+dr,c+dc)
self.captureCount+=1
self._remove()
# check for suicide and prevent it
self._helper.clear()
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,r,c)
self.toMove=-1*color
self._hashes.append(self._freshHash)
return True
def undoMove(self,r,c,captures):
if (r,c)!=PASS:
assert self.board[r][c]==-1*self.toMove, "{0}!={1}".format(self.board[r][c],-1*self.toMove)
if len(captures)>0:
self._helper.clear()
for (ri,ci) in captures:
self._helper.floodFill(EMPTY,ri,ci)
self._fill(self.toMove)
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)
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
self._freshHash=hashBoard(self.board)
self._hashes=[self._freshHash]
def hash(self):
return self._hashes[-1]
## 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._freshHash^=diffHash(r,c,self.board[r][c],filling)
self.board[r][c]=filling
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<boardSize and 0<=c+x<boardSize:
stack.append((r+y,c+x))
return False
|