Changeset - f669c32706e5
[Not reviewed]
default
0 3 2
Laman - 7 years ago 2018-04-13 18:15:48

refactoring: much of SourceFile.createDiagram moved to drawer, created drawer.Base class
5 files changed with 135 insertions and 113 deletions:
0 comments (0 inline, 0 general)
src/__init__.py
Show inline comments
 
new file 100644
src/diana.py
Show inline comments
 
import os
 
import re
 

	
 
from jinja2 import Environment,FileSystemLoader
 

	
 
import config as cfg
 
import go
 
from go import BLACK,WHITE,EMPTY
 
@@ -12,13 +10,6 @@ from drawer.svg import Svg
 
from drawer.tikz import Tikz
 

	
 

	
 
curDir=os.path.dirname(__file__)
 
templateDir=os.path.join(curDir,"templ")
 
env=Environment(loader=FileSystemLoader(templateDir))
 
env.trim_blocks=True
 
env.lstrip_blocks=True
 

	
 

	
 
def collectMoves(root):
 
	node=root
 
	while len(node.children)>0:
 
@@ -36,95 +27,55 @@ class SourceFile:
 
		self.fileName=fileName
 
		self._shortName= "".join(re.split(r'[/\\]', fileName)[-1].split('.')[:-1])
 
		self._game=go.Go()
 
		self._moveNumber=0
 
		self._record=None
 
		self._moves=[]
 

	
 
		games=Collection(open(self.fileName, 'r', encoding=cfg.encoding).read()).listGames()
 
		self._record=list(games)[0]
 
		self._moves=list(collectMoves(self._record.root))
 

	
 
	def process(self):
 
		print("{0}... ".format(self.fileName), end="")
 

	
 
		try:
 
			games=Collection(open(self.fileName, 'r', encoding=cfg.encoding).read()).listGames()
 
		except ParserError as e:
 
			print("Couldn't parse {0}, following error occured: {1}".format(self.fileName,e))
 
			return False
 
		self._record=list(games)[0]
 
		self._moves=list(collectMoves(self._record.root))
 

	
 
		diagramsNeeded=(len(self._moves)-cfg.minMovesPerDiagram)//cfg.movesPerDiagram+1
 

	
 
		for i in range(diagramsNeeded):
 
			self.createDiagram(i+1)
 
		i=1
 
		for k in range(0,len(self._moves),cfg.movesPerDiagram):
 
			filename=os.path.join(cfg.outputDir,"{0}-{1}".format(self._shortName,i))
 
			self.createDiagram(k,k+cfg.movesPerDiagram).save(filename,"templ-pleb.svg")
 
			i+=1
 

	
 
		notes=open(os.path.join(cfg.outputDir,"{0}.txt".format(self._shortName)), 'w')
 
		notes.write(self.createGameInfo())
 
		notes.close()
 
		print("done")
 

	
 
	def createDiagram(self,diagramNumber):
 
	def createDiagram(self,start,end):
 
		# initialize the diagram
 
		template=Svg()
 
		overlays=[]
 
		letters=dict()
 
		letter="a"
 

	
 
		self._setMove(start)
 

	
 
		# draw current state
 
		for lineNumber,line in enumerate(self._game.board):
 
			for itemNumber,item in enumerate(line):
 
				if item==BLACK: template.addStone(itemNumber,lineNumber,"b")
 
				if item==WHITE: template.addStone(itemNumber,lineNumber,"w")
 
			localBoard={(a,b):self._game.board[b][a]-1 for a in range(19) for b in range(19) if self._game.board[b][a]!=EMPTY}
 
				if item!=EMPTY: template.addStone(itemNumber,lineNumber,"b" if item==BLACK else "w")
 

	
 
		for j in range(cfg.movesPerDiagram):
 
			# draw the moves
 
			if self._moveNumber>=len(self._moves): break
 
		# draw the moves
 
		for k in range(start,end):
 
			if k>=len(self._moves): break
 

	
 
			c,move=self._moves[self._moveNumber]
 
			c=c.lower()
 
			color,move=self._moves[k]
 
			if move==tuple():
 
				overlays.append("{0} pass".format(self._moveNumber))
 
				self._moveNumber+=1
 
				template.overlays.append((k,"pass")) # !!
 
				continue
 
			else:
 
				(x,y)=move
 

	
 
			if not self._game.move(BLACK if c=='b' else WHITE, x,y):
 
				# !! we do not honor http://red-bean.com/sgf/ff5/m_vs_ax.htm at the moment
 
				msg="illegal move: {0} at {1},{2}".format(self._moveNumber+1,x,y)
 
				if cfg.keepBroken:
 
					print(msg)
 
					self._moveNumber+=1
 
					continue
 
				else:
 
					msg+=". aborted"
 
					print(msg)
 
					return False
 
				(c,r)=move
 

	
 
			# draw the move on an empty intersection
 
			if not (x,y) in localBoard:
 
				localBoard[(x,y)]=self._moveNumber+1
 
				template.addMove(x,y,c,self._moveNumber+1)
 
			# intersection occupied by an unlabeled stone
 
			elif localBoard[(x,y)]<1:
 
				# intersection not labeled even by a letter
 
				if not (x,y) in letters:
 
					letters[(x,y)]=letter
 
					color='b' if localBoard[(x,y)]==EMPTY else 'w'
 
					template.addMove(x,y,color,letter)
 
					letter=chr(ord(letter)+1)
 
				overlays.append("{0} = {1}".format(self._moveNumber+1,letters[(x,y)]))
 
			# intersection occupied by a numbered stone
 
			else: overlays.append("{0} = {1}".format(self._moveNumber+1,localBoard[(x,y)]))
 
			if not self._move(color,c,r):
 
				if cfg.keepBroken: continue
 
				else: return False
 

	
 
			self._moveNumber+=1
 
		
 
		# finish and save the diagram
 
		file=open(os.path.join(cfg.outputDir,"{0}-{1}.{2}".format(self._shortName,diagramNumber,template.extension)),'w') # a new file
 
		file.write(template.render(env.get_template("templ.svg")))
 
		file.close()
 
			# draw the move
 
			template.addMove(c,r,color,k+1)
 

	
 
		notes=open(os.path.join(cfg.outputDir,"{0}-{1}.txt".format(self._shortName,diagramNumber)), 'w')
 
		notes.write("\n".join(overlays))
 
		notes.close()
 
		return template
 

	
 
	def createGameInfo(self):
 
		rec=self._record
 
@@ -134,15 +85,38 @@ W: {white} {wRank}
 
{date}
 
{result}""".format(title=rec.get("GN",""), black=rec.get("PB",""), bRank=rec.get("BR",""), white=rec.get("PW",""), wRank=rec.get("WR",""), date=rec.get("DT",""), result=rec.get("RE",""))
 

	
 

	
 
print("processing:")
 
files=cfg.inputFiles[:]
 
	def _setMove(self,k):
 
		self._game=go.Go()
 
		for i in range(k):
 
			(color,move)=self._moves[i]
 
			if move==tuple(): continue # pass
 
			self._move(color,*move)
 

	
 
for item in files:
 
	if os.path.isfile(item):
 
		f=SourceFile(item)
 
		f.process()
 
	elif os.path.isdir(item):
 
		files+=[os.path.join(item,child) for child in os.listdir(item)]
 
		print("contents of the '{0}' directory added to the queue".format(item))
 
	else: print("the '{0}' path could not be resolved to either a file nor a directory".format(item))
 
	def _move(self,color,c,r):
 
		if not self._game.move(BLACK if color=='b' else WHITE, c,r):
 
			# !! we do not honor http://red-bean.com/sgf/ff5/m_vs_ax.htm at the moment
 
			msg="illegal move: {0} at {1},{2}".format(self._game.moveCount+1,c,r)
 
			if cfg.keepBroken:
 
				print(msg)
 
			else:
 
				msg+=". aborted"
 
				print(msg)
 
				return False
 
		return True
 

	
 

	
 
if __name__=="__main__":
 
	print("processing:")
 
	files=cfg.inputFiles[:]
 

	
 
	for item in files:
 
		if os.path.isfile(item):
 
			try:
 
				f=SourceFile(item)
 
				f.process()
 
			except ParserError as e:
 
				print("Couldn't parse {0}, following error occured: {1}".format(item,e))
 
		elif os.path.isdir(item):
 
			files+=[os.path.join(item,child) for child in os.listdir(item)]
 
			print("contents of the '{0}' directory added to the queue".format(item))
 
		else: print("the '{0}' path could not be resolved to either a file nor a directory".format(item))
src/drawer/base.py
Show inline comments
 
new file 100644
 
import os
 
from itertools import count
 

	
 
from jinja2 import Environment,FileSystemLoader
 

	
 

	
 
class DiagramPoint:
 
	def __init__(self,x,y,color="",label=""):
 
		self.x=x
 
		self.y=y
 
		self.color=color
 
		self.label=label
 

	
 
	def __repr__(self):
 
		return 'DiagramPoint({0},{1},"{2}","{3}")'.format(self.x,self.y,self.color,self.label)
 

	
 

	
 
class Base:
 
	highNumbers=True
 

	
 
	def __init__(self,start=0):
 
		self.overlays=[]
 
		self._letter="a"
 

	
 
		self._index=dict()
 
		self._indexGen=count(start)
 

	
 
		curDir=os.path.dirname(__file__)
 
		templateDir=os.path.join(curDir,"..","templ")
 
		self._env=Environment(loader=FileSystemLoader(templateDir))
 
		self._env.trim_blocks=True
 
		self._env.lstrip_blocks=True
 

	
 
	def addStone(self,x,y,color):
 
		assert (x,y) not in self._index
 
		self._index[(x,y)]=(next(self._indexGen),DiagramPoint(x,y,color))
 

	
 
	def addMove(self,x,y,color,label):
 
		if (not self.highNumbers) and isinstance(label,int) and label%100!=0:
 
			label%=100
 

	
 
		if (x,y) not in self._index:
 
			self._index[(x,y)]=(next(self._indexGen),DiagramPoint(x,y,color,label))
 
		else:
 
			(_,point)=self._index[(x,y)]
 
			if not point.label:
 
				point.label=self._letter
 
				self._letter=chr(ord(self._letter)+1)
 
			self.overlays.append((label, point.label))
 

	
 
	def addLabel(self,x,y,label):
 
		self._index[(x,y)]=(next(self._indexGen),DiagramPoint(x,y,"",label))
 

	
 
	def save(self,filename):
 
		notes=open(filename+".txt", 'w')
 
		notes.write("\n".join("{0} = {1}".format(a,b) for (a,b) in self.overlays))
 
		notes.close()
src/drawer/svg.py
Show inline comments
 
from itertools import count
 

	
 

	
 
c=28
 
padding=15
 
highNumbers=True
 
from .base import Base
 

	
 

	
 
def adjustFont(base,text):
 
@@ -24,38 +19,31 @@ class DiagramPoint:
 
		return 'DiagramPoint({0},{1},"{2}","{3}")'.format(self.x,self.y,self.color,self.label)
 

	
 

	
 
class Svg:
 
class Svg(Base):
 
	extension="svg"
 

	
 
	padding=15
 
	highNumbers=True
 
	
 
	def __init__(self):
 
	def __init__(self,start=0):
 
		super().__init__(start)
 
		self.boardSize=480
 
		self.padding=30
 

	
 
		self._index=dict()
 
		self._indexGen=count()
 

	
 
	def addStone(self,x,y,color):
 
		self._index[(x,y)]=(next(self._indexGen),DiagramPoint(x,y,color))
 

	
 
	def addMove(self,x,y,color,label):
 
		if (not self.highNumbers) and isinstance(label,int) and label%100!=0:
 
			label%=100
 

	
 
		self._index[(x,y)]=(next(self._indexGen),DiagramPoint(x,y,color,label))
 

	
 
	def addLabel(self,x,y,label):
 
		self._index[(x,y)]=(next(self._indexGen),DiagramPoint(x,y,"",label))
 

	
 
	def render(self, template):
 
	def render(self, templateName):
 
		points = [p for (i,p) in sorted(self._index.values(), key=lambda x: x[0])]
 

	
 
		stones = [p for p in points if p.color and not p.label]
 
		stones = [p for p in points if p.color and p.label==""]
 
		moves = [p for p in points if p.color and p.label]
 
		labels = [p for p in points if not p.color and p.label]
 

	
 
		params = {"boardSize":self.boardSize, "padding":self.padding, "stones":stones, "moves":moves, "labels":labels, "adjustFont":adjustFont}
 

	
 
		return template.render(params)
 
		return self._env.get_template(templateName).render(params)
 

	
 
	def save(self,filename,template="templ.svg"):
 
		file=open(filename+".svg",'w')
 
		file.write(self.render(template))
 
		file.close()
 

	
 
		super().save(filename)
src/go.py
Show inline comments
 
@@ -6,7 +6,9 @@ EMPTY=0
 
class Go:
 
	board=[[EMPTY]*19 for i in range(19)]
 
	
 
	def __init__(self): self.board=[[EMPTY]*19 for i in range(19)]
 
	def __init__(self):
 
		self.board=[[EMPTY]*19 for i in range(19)]
 
		self.moveCount=0
 
	
 
	def move(self,color,y,x):
 
		if self.board[x][y]!=EMPTY: return False
 
@@ -20,6 +22,7 @@ class Go:
 
		if not self._floodFill(color,x,y):
 
			self.board[x][y]=EMPTY
 
			return False
 
		self.moveCount+=1
 
		return True
 

	
 
	def _floodFill(self,color,x,y):
0 comments (0 inline, 0 general)