Changeset - 79f823432bb4
[Not reviewed]
default
0 3 0
Laman - 8 years ago 2017-01-07 16:17:22

nicer board logs
3 files changed with 28 insertions and 22 deletions:
0 comments (0 inline, 0 general)
src/go.py
Show inline comments
 
class Go:
 
	EMPTY=0
 
	BLACK=1
 
	WHITE=-1
 
EMPTY=0
 
BLACK=1
 
WHITE=-1
 
 
	## Initializes self.board to a list[r][c]=Go.EMPTY.
 
 
class Go:
 
	## Initializes self.board to a list[r][c]=EMPTY.
 
	def __init__(self,boardSize=19):
 
		self.boardSize=boardSize
 
		self.board=[[Go.EMPTY]*self.boardSize for x in range(boardSize)]
 
		self.board=[[EMPTY]*self.boardSize for x in range(boardSize)]
 
 
	## Executes a move.
 
	#
 
	#  Doesn't check for kos. Suicide not allowed.
 
	#
 
	#  @param color Go.BLACK or Go.WHITE
 
	#  @param color BLACK or WHITE
 
	#  @return True on success, False on failure (illegal move)
 
	def move(self,color,row,col):
 
		if self.board[row][col]!=Go.EMPTY: return False
 
		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.temp=[[False]*self.boardSize for x in self.board]
 
			if not self._floodFill(-color,row+r,col+c): self._remove()
 
 
		# check for suicide
 
		self.temp=[[False]*self.boardSize for x in self.board]
 
		if not self._floodFill(color,row,col):
 
			self.board[row][col]=Go.EMPTY
 
			self.board[row][col]=EMPTY
 
			return False
 
		return True
 
 
	## 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]==Go.EMPTY: return True # found a liberty
 
		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]=Go.EMPTY
 
				if self.temp[r][c]: self.board[r][c]=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)
src/gui/__init__.py
Show inline comments
 
@@ -5,13 +5,13 @@ from PIL import ImageTk
 
import PIL
 
 
import config
 
from epoint import EPoint
 
from corners import Corners
 
import image_analyzer
 
from go import Go
 
import go
 
from grid import Grid
 
 
 
class MainWindow(tk.Frame):
 
	def __init__(self,parent,master=None):
 
		self.parent=parent
 
@@ -148,16 +148,16 @@ class BoardView(tk.Canvas):
 
	## Draws a stone at provided coordinates.
 
	#
 
	#  For an unknown color draws nothing and returns False.
 
	#
 
	#  @param r row coordinate, [0-18], counted from top
 
	#  @param c column coordinate, [0-18], counted from left
 
	#  @param color color indicator, Go.BLACK or Go.WHITE
 
	#  @param color color indicator, go.BLACK or go.WHITE
 
	def drawStone(self,r,c,color):
 
		if color==Go.BLACK: hexCode='#000000'
 
		elif color==Go.WHITE: hexCode='#ffffff'
 
		if color==go.BLACK: hexCode='#000000'
 
		elif color==go.WHITE: hexCode='#ffffff'
 
		else: return False
 
		r+=1
 
		c+=1
 
		self.create_oval(c*18-9,r*18-9,c*18+9,r*18+9,fill=hexCode)
 
 
src/image_analyzer.py
Show inline comments
 
import logging as log
 
from grid import Grid
 
from go import Go
 
from go import exportBoard
 
import go
 
 
 
class ImageAnalyzer:
 
 
	def __init__(self,tresB=30,tresW=60):
 
		self.board=[[Go.EMPTY]*19 for r in range(19)]
 
		self.board=[[go.EMPTY]*19 for r in range(19)]
 
		self.grid=None
 
 
		self.tresB=tresB
 
		self.tresW=tresW
 
 
	# let's not concern ourselves with sizecoef and shift here anymore. we want corners to come already properly recomputed
 
@@ -21,14 +22,13 @@ class ImageAnalyzer:
 
		for r in range(19):
 
			for c in range(19):
 
				intersection=self.grid.intersections[r][c]
 
 
				self.board[r][c]=self.analyzePoint(image,r,c,intersection,*(self.grid.stoneSizeAt(r,c)))
 
 
		boardStr="\n".join(str(row) for row in self.board)
 
		log.info("board analyzed:\n%s",boardStr)
 
		log.info("board analyzed:\n%s", exportBoard(self.board))
 
 
	def analyzePoint(self,image,row,col,imageCoords,stoneWidth,stoneHeight):
 
		b=w=e=0
 
 
		((x1,y1),(x2,y2))=relevantRect(imageCoords,stoneWidth,stoneHeight)
 
 
@@ -42,15 +42,15 @@ class ImageAnalyzer:
 
				if 100*I<self.tresB: b+=1
 
				elif 100*I>self.tresW: w+=1
 
				else: e+=1
 
 
		log.debug("(%d,%d) ... (b=%d,w=%d,e=%d)", row, col, b, w, e)
 
 
		if b>=w and b>=e: return Go.BLACK
 
		if w>=b and w>=e: return Go.WHITE
 
		return Go.EMPTY
 
		if b>=w and b>=e: return go.BLACK
 
		if w>=b and w>=e: return go.WHITE
 
		return go.EMPTY
 
 
	def setGridCorners(self,corners):
 
		self.grid=Grid(corners)
 
 
 
def relevantRect(imageCoords,stoneWidth,stoneHeight):
0 comments (0 inline, 0 general)