import os import re from jinja2 import Environment,FileSystemLoader import config as cfg import go from go import BLACK,WHITE,EMPTY from sgfParser import ParserError from sgfParser.collection import Collection 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)) def collectMoves(root): node=root while len(node.children)>0: b=node.getProp("B") w=node.getProp("W") if b is not None: yield ("b",b) elif w is not None: yield ("w",w) # else: yield None # !! not really robust node=node.children[0] class SourceFile: def __init__(self,fileName): 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=[] 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) 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): # initialize the diagram template=Svg() overlays=[] letters=dict() letter="a" 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} for j in range(cfg.movesPerDiagram): # draw the moves if self._moveNumber>=len(self._moves): break c,move=self._moves[self._moveNumber] c=c.lower() if move==tuple(): overlays.append("{0} pass".format(self._moveNumber)) self._moveNumber+=1 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 # 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)])) 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() notes=open(os.path.join(cfg.outputDir,"{0}-{1}.txt".format(self._shortName,diagramNumber)), 'w') notes.write("\n".join(overlays)) notes.close() def createGameInfo(self): rec=self._record return """{title} B: {black} {bRank} 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[:] 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))