Files
@ 077600f0c5f8
Branch filter:
Location: OneEye/src/go/core.py
077600f0c5f8
3.1 KiB
text/x-python
engine v1 mostly finished
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 | 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
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
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 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<boardSize and 0<=c+x<boardSize:
stack.append((r+y,c+x))
return False
|