Files
@ 782476e472ab
Branch filter:
Location: OneEye/src/go.py - annotation
782476e472ab
3.5 KiB
text/x-python
configurable image directory, refactored constants
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 | b197a19e4afe b197a19e4afe 782476e472ab b197a19e4afe b197a19e4afe b197a19e4afe 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 2fcaffe8cb70 2fcaffe8cb70 b197a19e4afe b197a19e4afe 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 782476e472ab 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 2fcaffe8cb70 0d57edb8be11 0d57edb8be11 0d57edb8be11 2fcaffe8cb70 0d57edb8be11 0d57edb8be11 0d57edb8be11 b197a19e4afe b197a19e4afe 0d57edb8be11 0d57edb8be11 b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 2fcaffe8cb70 0d57edb8be11 0d57edb8be11 2fcaffe8cb70 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 0d57edb8be11 2fcaffe8cb70 0d57edb8be11 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 0d57edb8be11 b197a19e4afe 0d57edb8be11 0d57edb8be11 0d57edb8be11 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe b197a19e4afe 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 2fcaffe8cb70 | import logging as log
from util import EMPTY,BLACK,WHITE,colorNames
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._temp=[[EMPTY]*boardSize for x in range(boardSize)]
self.toMove=BLACK
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 move(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._clearTemp()
if not self._floodFill(-color,row+r,col+c): self._remove()
# check for suicide
self._clearTemp()
if not self._floodFill(color,row,col):
self.board[row][col]=EMPTY
return False
self._record.move(color,row,col)
self.toMove=-1*color
return True
def transitionMove(self,board):
res=transitionMove(self.board,board)
if not res: return res
(r,c,color)=res
return self.move(color,r,c)
## Checks for liberties of a stone at given coordinates.
#
# The stone's group is marked with True in self.temp, ready for capture if needed. Recursively called for stone's neighbors.
#
# @return True if alive, False if captured
def _floodFill(self,color,row,col):
if col<0 or col>=self.boardSize or row<0 or row>=self.boardSize: return False # out of range
if self._temp[row][col]: return False # already visited
if self.board[row][col]==EMPTY: return True # found a liberty
if self.board[row][col]!=color: return False # opponent's stone
self._temp[row][col]=True # set visited
return self._floodFill(color,row,col-1) or self._floodFill(color,row,col+1) or self._floodFill(color,row-1,col) or self._floodFill(color,row+1,col) # check neighbors
## Removes stones at coordinates marked with True in self.temp.
def _remove(self):
for r in range(self.boardSize):
for c in range(self.boardSize):
if self._temp[r][c]: self.board[r][c]=EMPTY
def _clearTemp(self):
for i in range(self.boardSize):
for j in range(self.boardSize):
self._temp[i][j]=EMPTY
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
|