diff --git a/src/diana.py b/src/diana.py --- a/src/diana.py +++ b/src/diana.py @@ -3,11 +3,18 @@ import re import sys import go -import sgf +from go import BLACK,WHITE,EMPTY +from sgfParser.collection import Collection from drawer.svg import Svg from drawer.tikz import Tikz + +templateDir=os.path.join(os.path.dirname(__file__),"templ") +with open(os.path.join(templateDir,"templ.svg")) as f: + template=f.read() + + if len(sys.argv)>1: files=sys.argv[1:] else: @@ -19,14 +26,28 @@ minMovesPerDiagram=10 t=sys.stdout +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] + + def processFile(fileName): shortName="".join(re.split(r'[/\\]',fileName)[-1].split('.')[:-1]) game=go.Go() global t - - record=sgf.Sgf(open(fileName, 'r', encoding="utf-8").read()) - moves=record.getMoves() + + games=Collection(open(fileName, 'r', encoding="utf-8").read()).listGames() + record=list(games)[0] + + moves=list(collectMoves(record)) localBoard=dict() overlays="" @@ -37,52 +58,51 @@ def processFile(fileName): moveNumber=0 for i in range(diagramsNeeded): - # inicializuj diagram - diagram=Tikz() + # initialize the diagram + diagram=Svg() for lineNumber,line in enumerate(game.board): for itemNumber,item in enumerate(line): - if item==1: diagram.drawStone(itemNumber,lineNumber,"b") - if item==-1: diagram.drawStone(itemNumber,lineNumber,"w") - localBoard={(a,b):game.board[b][a]-1 for a in range(19) for b in range(19) if game.board[b][a]!=0} + if item==BLACK: diagram.addStone(itemNumber,lineNumber,"b") + if item==WHITE: diagram.addStone(itemNumber,lineNumber,"w") + localBoard={(a,b):game.board[b][a]-1 for a in range(19) for b in range(19) if game.board[b][a]!=EMPTY} for j in range(movesPerDiagram): - # kresli tahy + # draw the moves if moveNumber>=len(moves): break - + c,(x,y)=moves[moveNumber] c=c.lower() - if not game.move(1 if c=='b' else -1,x,y): + if not game.move(BLACK if c=='b' else WHITE, x,y): print("illegal move: {0} at {1},{2}".format(moveNumber+1,x,y)) moveNumber+=1 continue - - # zapíšu tah na volný průsečík + + # draw the move on an empty intersection if not (x,y) in localBoard: localBoard[(x,y)]=moveNumber+1 - diagram.drawMove(x,y,moveNumber+1,c) - # průsečík je obsazený nepopsaným kamenem + diagram.addMove(x,y,c,moveNumber+1) + # intersection occupied by an unlabeled stone elif localBoard[(x,y)]<1: - # průsečík není popsaný ani písmenem + # intersection not labeled even by a letter if not (x,y) in letters: letters[(x,y)]=letter - color='b' if localBoard[(x,y)]==0 else 'w' - diagram.drawMove(x,y,letter,color) + color='b' if localBoard[(x,y)]==EMPTY else 'w' + diagram.addMove(x,y,color,letter) letter=chr(ord(letter)+1) overlays+="{0} = {1}\n".format(moveNumber+1,letters[(x,y)]) - # průsečík je obsazený očíslovaným kamenem + # intersection occupied by a numbered stone else: overlays+="{0} = {1}\n".format(moveNumber+1,localBoard[(x,y)]) moveNumber+=1 - # dokonči a ulož diagram - # TODO rozumně pracovat s adresáři - t=open(os.path.join(os.path.dirname(__file__),"out","{0}-{1}.{2}".format(shortName,i+1,diagram.extension)),'w') # nový soubor - t.write(diagram.getContent()) + # finish and save the diagram + t=open(os.path.join("out","{0}-{1}.{2}".format(shortName,i+1,diagram.extension)),'w') # a new file + t.write(diagram.render(template)) t.close() - notes=open(os.path.join(os.path.dirname(__file__),"out","{0}.txt".format(shortName)),'w') + notes=open(os.path.join("out","{0}.txt".format(shortName)),'w') notes.write(overlays) notes.close() diff --git a/src/drawer/svg.py b/src/drawer/svg.py old mode 100644 new mode 100755 --- a/src/drawer/svg.py +++ b/src/drawer/svg.py @@ -1,72 +1,64 @@ +from jinja2 import Template + + c=28 padding=15 highNumbers=True +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 Svg: - content="" - footer="" extension="svg" padding=15 - gridSize=28 highNumbers=True def __init__(self): - self.content=''' - - - - - \n'''.format(2*self.padding+18*self.gridSize) - self.footer="\n" + self.boardSize=480 + self.padding=30 + + self._index=dict() + + def addStone(self,x,y,color): + self._index[(x,y)]=(len(self._index),DiagramPoint(x,y,color)) - grid=' \n' + def addMove(self,x,y,color,label): + if (not self.highNumbers) and isinstance(label,int) and label%100!=0: + label%=100 - # okraje desky - for i in (0,18): - self.content+=' \n'.format(self.padding, 18*self.gridSize+self.padding, self.gridSize*i+self.padding, self.gridSize*i+self.padding) - self.content+=' \n'.format(self.gridSize*i+self.padding, self.gridSize*i+self.padding, self.padding, 18*self.gridSize+self.padding) - - # mřížka - for i in range(1,18): - self.content+=grid.format(self.padding, 18*self.gridSize+self.padding, c*i+self.padding, c*i+self.padding) - self.content+=grid.format(c*i+self.padding, c*i+self.padding, self.padding, 18*c+self.padding) + self._index[(x,y)]=(len(self._index),DiagramPoint(x,y,color,label)) + + def addLabel(self,x,y,label): + self._index[(x,y)]=(len(self._index),DiagramPoint(x,y,"",label)) - # hvězdy - for i in range(3): - for j in range(3): - self.content+=' \n'.format(padding+3*c+6*i*c, padding+3*c+6*j*c, 2) - - def __str__(self): - return self.content+self.footer - - def drawStone(self,x,y,color): - self.content+=' \n'.format(padding+x*c, padding+y*c, c/2-1, color) + def render(self, template): + points = [p for (i,p) in sorted(self._index.values())] - def getFontSize(self,text): - if len(text)<2: return round(0.7*c) - elif len(text)<3: return round(0.55*c) - else: return round(0.4*c) + stones = [p for p in points if p.color and not 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] + + svg = Template(template) + params = {"boardSize":self.boardSize, "padding":self.padding, "stones":stones, "moves":moves, "labels":labels} - def writeLabel(self,x,y,label,color): - label=str(label) - fontSize=self.getFontSize(label) - self.content+=' {4}\n'.format(padding+x*c, padding+y*c+0.35*fontSize, color, fontSize, label) - - def drawMove(self,x,y,label,color): - labelColor="w" if color=="b" else "b" - - if (not self.highNumbers) and isinstance(label,int) and label%100!=0: label=label%100 # dost neobratná logika - - self.drawStone(x,y,color) - self.writeLabel(x,y,label,labelColor) - - def getContent(self): - return self.content+self.footer + return svg.render(params) + + # def getFontSize(self,text): + # if len(text)<2: return round(0.7*c) + # elif len(text)<3: return round(0.55*c) + # else: return round(0.4*c) + # + # def writeLabel(self,x,y,label,color): + # label=str(label) + # fontSize=self.getFontSize(label) + # self.content+=' {4}\n'.format(padding+x*c, padding+y*c+0.35*fontSize, color, fontSize, label) diff --git a/src/go.py b/src/go.py --- a/src/go.py +++ b/src/go.py @@ -1,12 +1,15 @@ -class Go: - # 1: B, 0: _, -1: W - # resp. jakákoli čísla s opačnými znaménky - board=[[0]*19 for i in range(19)] +BLACK=1 +WHITE=-1 +EMPTY=0 + + +class Go: + board=[[EMPTY]*19 for i in range(19)] - def __init__(self): self.board=[[0]*19 for i in range(19)] + def __init__(self): self.board=[[EMPTY]*19 for i in range(19)] def move(self,color,y,x): - if self.board[x][y]!=0: return False + if self.board[x][y]!=EMPTY: return False self.board[x][y]=color @@ -15,14 +18,14 @@ if not self._floodFill(-color,x+i,y+j): self._remove() self.temp=[[False]*19 for i in range(19)] if not self._floodFill(color,x,y): - self.board[x][y]=0 + self.board[x][y]=EMPTY return False return True def _floodFill(self,color,x,y): if x<0 or x>18 or y<0 or y>18: return False if self.temp[x][y]: return False - if self.board[x][y]==0: return True + if self.board[x][y]==EMPTY: return True if self.board[x][y]!=color: return False self.temp[x][y]=True return self._floodFill(color,x-1,y) or self._floodFill(color,x+1,y) or self._floodFill(color,x,y-1) or self._floodFill(color,x,y+1) @@ -30,4 +33,4 @@ def _remove(self): for i in range(19): for j in range(19): - if self.temp[i][j]: self.board[i][j]=0 + if self.temp[i][j]: self.board[i][j]=EMPTY diff --git a/src/sgfParser/node.py b/src/sgfParser/node.py --- a/src/sgfParser/node.py +++ b/src/sgfParser/node.py @@ -67,8 +67,8 @@ class Node: res.setChildren(self.children[:]) return res - def getProperty(self,name): - if name in self.properties: return self.properties[name] + def getProp(self,name): + if name in self.properties: return self.properties[name].value else: return None ## Returns textual representation of the Node itself, but disregards its children. diff --git a/src/templ/templ.svg b/src/templ/templ.svg new file mode 100755 --- /dev/null +++ b/src/templ/templ.svg @@ -0,0 +1,53 @@ + +{% set cellSize=boardSize/18 %} +{% set stoneRadius=cellSize/2-1 %} + + + + + + + + {# grid #} + {% for i in range(1,18) %} + + + {% endfor %} + + {# stars #} + {% for y in [3,9,15] %} + {% for x in [3,9,15] %} + + {% endfor %} + {% endfor %} + + {# stones #} + {% for p in stones %} + + {% endfor %} + + {# moves #} + {% for p in moves %} + + + {{p.label}} + + {% endfor %} + + {# labels #} + {% for p in labels %} + + + {{p.label}} + + {% endfor %} + +