Changeset - a81abb4e0968
[Not reviewed]
default
0 3 1
Laman - 9 years ago 2016-09-10 12:45:35

fixed sgfParser, added complex sgf test
2 files changed:
Changeset was too big and was cut off... Show full diff anyway
0 comments (0 inline, 0 general)
src/diana/diana.py
Show inline comments
 
import os
 
import re
 
import sys
 
 
import diana.sgf as sgf
 
import diana.go as go
 
import sgf
 
import go
 
 
if len(sys.argv)>1:
 
	files=sys.argv[1:]
 
else:
 
	sys.exit("no input file specified")
 
 
movesPerDiagram=75
 
minMovesPerDiagram=10
 
 
t=sys.stdout
 
c=28
 
padding=15
 
highNumbers=True
 
 
class Svg:
 
	content=""
 
	footer=""
 
	extension="svg"
 
 
	padding=15
 
	gridSize=28
 
	highNumbers=True
 
	
 
	def __init__(self):
 
		self.content='''<?xml version="1.0" standalone="no"?>
 
<svg width="{0}" height="{0}" version="1.1" xmlns="http://www.w3.org/2000/svg" alignment-baseline="center">
 
	<defs>
 
		<style type="text/css"><![CDATA[
 
		text{{font-family:"DejaVu Sans";text-anchor:middle;}}
 
		line{{stroke:black;stroke-width:0.7}}
 
		circle{{stroke:black}}
 
		.b{{fill:black}}
 
		.w{{fill:white}}
 
		]]></style>
 
	</defs>
 
	<rect width="{0}" height="{0}" x="0" y="0" style="fill:white;stroke:white"/>\n'''.format(2*self.padding+18*self.gridSize)
 
		self.footer="</svg>\n"
 
 
		grid='  <line x1="{0}" x2="{1}" y1="{2}" y2="{3}" />\n'
 
 
		# okraje desky
 
		for i in (0,18):
 
			self.content+='  <line x1="{0}" x2="{1}" y1="{2}" y2="{3}" style="stroke-width:1"/>\n'.format(self.padding, 18*self.gridSize+self.padding, self.gridSize*i+self.padding, self.gridSize*i+self.padding)
 
			self.content+='  <line x1="{0}" x2="{1}" y1="{2}" y2="{3}" style="stroke-width:1"/>\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(padding, 18*c+padding, c*i+padding, c*i+padding)
 
			self.content+=grid.format(c*i+padding, c*i+padding, padding, 18*c+padding)
 
 
		# hvězdy
 
		for i in range(3):
 
			for j in range(3):
 
				self.content+='  <circle cx="{0}" cy="{1}" r="{2}" class="b"/>\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+='  <circle cx="{0}" cy="{1}" r="{2}" class="{3}" />\n'.format(padding+x*c, padding+y*c, c/2-1, color)
 
 
	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+='  <text x="{0}" y="{1}" class="{2}" font-size="{3}">{4}</text>\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
 
 
 
class Tikz:
 
	content=""
 
	footer=""
 
	extension="tex"
 
	
 
	highNumbers=True
 
	
 
	def __init__(self):
 
		self.content=r'''\begin{tikzpicture}
 
	\draw[step=\boardSquare,gray,very thin] (0,0) grid (18\boardSquare,18\boardSquare);
 
	\draw (0,0) rectangle (18\boardSquare,18\boardSquare);
 
	
 
	'''
src/diana/sgfParser.py
Show inline comments
 
import re
 
 
def skipWhitespace(str,start):
 
	i=start
 
	while i<len(str) and str[i].isspace(): i+=1
 
	return i
 
 
class Collection:
 
	gameTrees=[]
 
	
 
	def __init__(self,str):
 
		self.gameTrees=[]
 
		i,x=GameTree.create(str,0)
 
		if x is None:
 
			print("error when parsing Collection")
 
			return
 
		while x is not None:
 
			self.gameTrees.append(x)
 
			i,x=GameTree.create(str,i)
 
	
 
class GameTree:
 
	nodes=[]
 
	branches=[]
 
	def __init__(self):
 
		self.nodes=[]
 
		self.branches=[]
 
	
 
	# def __init__(self,str,start):
 
		# self.nodes=[]
 
		# self.branches=[]
 
		# if str[start]!="(":
 
			# print("error when parsing GameTree")
 
			# return (-1,None)
 
		# i,x=Node(str,start+1)
 
		# if x is None:
 
			# print("error when parsing GameTree")
 
			# return (-1,None)
 
		# while x is not None:
 
			# self.nodes.append(x)
 
			# i,x=Node(str,i)
 
		# if str[i]!=")":
 
			# print("error when parsing GameTree")
 
			# return (-1,None)
 
		# return (i+1,self)
 
		
 
	@staticmethod
 
	def create(str,start):
 
		res=GameTree()
 
		i=skipWhitespace(str,start)
 
		if i>=len(str) or str[i]!="(":
 
			# print("error when parsing GameTree")
 
			return (start,None)
 
		i,x=Node.create(str,start+1)
 
		if x is None:
 
			# print("error when parsing GameTree")
 
			return (i,None)
 
		while x is not None:
 
			res.nodes.append(x)
 
			i=skipWhitespace(str,i)
 
			i,x=Node.create(str,i)
 
		i=skipWhitespace(str,i)
 
		i,x=GameTree.create(str,i)
 
		while x is not None:
 
			res.branches.append(x)
 
			i=skipWhitespace(str,i)
 
			i,x=GameTree.create(str,i)
 
		if str[i]!=")":
 
			# print("error when parsing GameTree")
 
			return (i,None)
 
		return (i+1,res)
 
	
 
class Node:
 
	properties=dict()
 
	def __init__(self):
 
		self.properties=dict()
 
	
 
	@staticmethod
 
	def create(str,start):
 
		res=Node()
 
		if str[start]!=";":
 
			# print("error when parsing Node")
 
			return (start,None)
 
		i=skipWhitespace(str,start+1)
 
		i,x=Property.create(str,start+1)
 
		while x is not None:
 
			if x.name in res.properties:
 
				print('error: duplicate "{0}" property in node at position {1}. second value ignored'.format(x.name,start))
 
				print(res.properties)
 
				raise ParserError(0,0,'duplicate "{0}" property in node at position {1}. second value ignored'.format(x.name,start))
 
			else:
 
				res.properties[x.name]=x
 
			i=skipWhitespace(str,i)
 
			i,x=Property.create(str,i)
 
		return (i,res)
 
		
 
	def setProperty(self,name,value):
 
		self.properties[name]=value
 
		# zkontrolovat typ value
 
		
 
	def getProperty(self,name):
 
		if name in self.properties: return self.properties[name]
 
		else: return None
 
	
 
class Property:
 
	name=""
 
	value=""
 
	def __init__(self):
 
		self.name=""
 
		self.value=""
 
	
 
	@staticmethod
 
	def create(str,start):
 
		res=Property()
 
		i,x=Property.ident(str,start)
 
		if x is None:
 
			return (start,None)
 
		res.name=x
 
		i,x=PropValue.create(str,i,res.name)
 
		if x is None:
 
			print('error when parsing property "{0}" at position {1}'.format(res.name,i))
 
			return (start,None)
 
		# while x is not None: # přesunuto do PropValue.listOf
 
			# res.values.append(x)
 
			# i=skipWhitespace(str,i)
 
			# i,x=PropValue.create(str,i,res.name)
 
		return (i,res)
 
		
 
	@staticmethod
 
	def ident(str,start):
 
		r=re.compile(r"[A-Z]+")
 
		m=r.match(str,start)
 
		if m is None: return (start,None)
 
		return (m.end(),m.group())
 
 
class PropValue:
 
	type=""
 
	value=None
 
	def __init__(self):
 
		self.type=""
 
		self.value=None
 
 
	patterns=dict()
 
	
 
	@staticmethod
 
	def create(str,start,name):
 
		if name in PropValue.patterns:
 
			return PropValue.patterns[name](str,start)
 
		else:
 
			print('warning, unknown property "{0}" at position {1}'.format(name,start))
 
			return PropValue.singleton(PropValue.anything)(str,start)
 
	
 
	# def singleton(str,start,vType):
 
		# if str[start]!="[":
 
			# return (start,None)
 
		# i,x=vType(str,start+1)
 
		# if x is None: return (start,None)
 
		# if str[i]!="]":
 
			# return (start,None)
 
		# return (i+1,x)
 
	
 
	def choose(*vTypes):
 
		def f(str,start):
 
			for vType in vTypes:
 
				i,x=vType(str,start)
 
				if x is not None: return (i,x)
 
			return (start,None)
 
		return f
 
	
 
	def singleton(vType):
 
		def f(str,start):
 
			if str[start]!="[":
 
				return (start,None)
 
			i,x=vType(str,start+1)
 
			if x is None: return (start,None)
 
			if str[i]!="]":
 
				return (start,None)
 
			return (i+1,x)
 
		return f
 
		
 
	# def listOf(str,start,vType,allowEmpty=False):
 
		# res=[]
 
		# i,x=singleton(str,start,vType)
 
		# # singleton(vType) if vType not tuple else compose(vType[0],vType[1])
 
		# while x!=None:
 
			# res.append(x)
 
			# i,x=singleton(str,i,vType)
 
		# if len(res)==0 and not allowEmpty: return (start,None)
 
		# return (i,res)
 
		
 
	def listOf(vType,allowEmpty=False):
 
		def f(str,start):
 
			res=[]
 
			single=singleton(vType)
 
			single=PropValue.singleton(vType)
 
			i,x=single(str,start)
 
			while x!=None:
 
				res.append(x)
 
				i,x=single(str,i)
 
			if len(res)==0 and not allowEmpty: return (start,None)
 
			return (i,res)
 
		return f
 
		
 
	# def compose(str,start,vTypeA,vTypeB):
 
		# i,a=vTypeA(str,start)
 
		# if a==None or str[i]!=":": return (start,None)
 
		# i,b=vTypeB(str,i+1)
 
		# if b==None: return start,None
 
		# return (i,(a,b))
 
		
 
	def compose(vTypeA,vTypeB):
 
		def f(str,start):
 
			i,a=vTypeA(str,start)
 
			# print(">",i,a)
 
			if a==None or str[i]!=":": return (start,None)
 
			i,b=vTypeB(str,i+1)
 
			# print(">",i,b)
 
			if b==None: return start,None
 
			return (i,(a,b))
 
		return f
 
	
 
	def number(str,start):
 
		r=re.compile(r"(\+|-|)\d+")
 
		m=r.match(str,start)
 
		if m is None: return (start,None)
 
		res=int(m.group(0))
 
		return (m.end(),res)
 
		
 
	def real(str,start):
 
		r=re.compile(r"(\+|-|)\d+(\.\d+)?")
 
		m=r.match(str,start)
 
		if m is None: return (start,None)
 
		res=float(m.group(0))
 
		return (m.end(),res)
 
		
 
	def double(str,start):
 
		r=re.compile(r"1|2")
 
		m=r.match(str,start)
 
		if m is None: return (start,None)
 
		res=int(m.group(0))
 
		return (m.end(),res)
 
	
 
	def color(str,start):
 
		r=re.compile(r"B|W")
 
		m=r.match(str,start)
 
		if m is None: return (start,None)
 
		return (m.end(),m.group(0))
 
		
 
	# def simpleText(str,start):
 
		# res=""
 
		# esc=False
 
		# lineBreak=False
 
		# for c in str:
 
			# if esc:
 
				# res+=c
 
				# esc=False
 
			# elif c=="\\":
 
				# esc=True
 
			# elif c=="]":
 
				# break
 
			# else:
 
				# res+=c
 
		# return res
 
	
 
	def text(simple=True,composed=False):
 
		def f(str,start):
 
			res=""
 
			esc=False
 
			lastC=""
 
			for i,c in enumerate(str[start:],start):
 
				if esc:
 
					if c!="\n" and c!="\r": res+=c
 
					esc=False
 
				elif (c=="\n" and lastC=="\r") or (c=="\r" and lastC=="\n"): pass
 
				elif c=="\r" or c=="\n" and not simple:
 
					res+="\n"
 
				elif c.isspace():
 
					res+=" "
 
				elif c=="\\":
 
					esc=True
 
				elif c=="]" or (c==":" and composed):
 
					break
 
				else:
 
					res+=c
 
				lastC=c
 
			return (i,res)
 
		return f
 
		
 
	def empty(str,start): return (start,"")
 
	
 
	def anything(str,start):
 
		esc=False
 
		for i,c in enumerate(str[start:],start):
 
			if esc: esc=False
 
			elif c=="\\": esc=True
 
			elif c=="]": break
 
		return (i,str[start:i])
 
	
 
	# go specific
 
	def point(str,start):
 
		r=re.compile(r"[a-zA-Z]{2}|") # !! limit to board size
 
		m=r.match(str,start)
 
		if m is None: return (start,None)
 
		if m.group(0)=="": # pass, !! tt
 
			return (m.end(),tuple())
 
		col=m.group(0)[0]
 
		row=m.group(0)[1]
 
		col=ord(col) - (ord("a") if "a"<=col<="z" else ord("A")-26)
 
		row=ord(row) - (ord("a") if "a"<=row<="z" else ord("A")-26)
 
		return (m.end(),(col,row))
 
 
	move=point
 
	stone=point
 
	
 
	patterns={
 
		"B":singleton(move),
 
		"KO":singleton(empty),
 
		"MN":singleton(number),
 
		"W":singleton(move),
 
		"AB":listOf(stone), #
 
		"AE":listOf(point), #
 
		"AW":listOf(stone), #
 
		"PL":singleton(color),
 
		"C":singleton(text(simple=False)),
 
		"DM":singleton(double),
 
		"GB":singleton(double),
 
		"GW":singleton(double),
 
		"HO":singleton(double),
 
		"N":singleton(text()),
 
		"UC":singleton(double),
 
		"V":singleton(real),
 
		"BM":singleton(double),
 
		"DO":singleton(empty),
 
		"IT":singleton(empty),
 
		"TE":singleton(double),
 
		"AR":listOf(compose(point,point)), #
 
		"CR":listOf(point), #
 
		"DD":listOf(point,allowEmpty=True), #
 
		"LB":listOf(compose(point,text())), #
 
		"LN":listOf(compose(point,point)), #
 
		"MA":listOf(point), #
 
		"SL":listOf(point), #
 
		"SQ":listOf(point), #
 
		"TR":listOf(point), #
 
		"AP":singleton(compose(text(composed=True),text())), #
 
		"CA":singleton(text()),
 
		"FF":singleton(number),
 
		"GM":singleton(number),
 
		"ST":singleton(number),
 
		"SZ":choose(singleton(number),singleton(compose(number,number))), #
 
		"AN":singleton(text()),
 
		"BR":singleton(text()),
 
		"BT":singleton(text()),
 
		"CP":singleton(text()),
 
		"DT":singleton(text()),
 
		"EV":singleton(text()),
 
		"GN":singleton(text()),
 
		"GC":singleton(text(simple=False)),
 
		"ON":singleton(text()),
 
		"OT":singleton(text()),
 
		"PB":singleton(text()),
 
		"PC":singleton(text()),
 
		"PW":singleton(text()),
 
		"RE":singleton(text()),
 
		"RO":singleton(text()),
 
		"RU":singleton(text()),
 
		"SO":singleton(text()),
 
		"TM":singleton(real),
 
		"US":singleton(text()),
 
		"WR":singleton(text()),
 
		"WT":singleton(text()),
 
		"BL":singleton(real),
 
		"OB":singleton(number),
 
		"OW":singleton(number),
 
		"WL":singleton(real),
 
		"FG":choose(singleton(empty),singleton(compose(number,text()))), #
 
		"PM":singleton(number),
 
		"VW":listOf(point,allowEmpty=True), #
 
		
 
		# go specific
 
		"HA":singleton(number),
 
		"KM":singleton(real),
 
		"TB":listOf(point,allowEmpty=True),
 
		"TW":listOf(point,allowEmpty=True)
 
	}
 
 
class ParserError(Exception):
 
	def __init__(self,line,col,message):
 
		self.line=line
 
		self.col=col
 
		self.message=message
 
 
 
 
"""def property(str):
 
	# i=propIdent(str)
 
	# if i<0: return -1
 
	# j=i
 
	# i=propValue(str[i:])
 
	# while i>=0:
 
		# j+=i
 
		# i=propValue(str[i:])
 
	# return j
 
 
def propIdent(str):
 
	m=re.match(r"[A-Z]+",str)
 
	if m is None: return -1
 
	return m.end()
 
 
def propValue(str):
 
	i=cValueType(str[1:])
 
	if str[0]=="[" and i>=0 and str[i]=="]": return i+1
 
	else: return -1
 
 
class propValue:
 
	pass
 
 
def cValueType(str,start):
 
	matches=[real,number,double,color,simpleText]
 
	for f in matches:
 
		i,x=f(str,start)
 
		if x is not None: return i,x
 
	return 1/0
 
 
def number(str,start):
 
	r=re.compile(r"(\+|-|)\d+")
 
	m=r.match(str,start)
 
	if m is None: return (-1,None)
 
	x=int(m.group(0))
 
	return (m.end(),x)
 
 
def real(str):
 
	m=re.match(r"(\+|-|)\d+(\.\d+)?",str)
 
	if m is None: return -1
 
	return m.end()
 
 
def double(str):
 
	m=re.match(r"1|2",str)
 
	if m is None: return -1
 
	return m.end()
 
	
 
def color(str):
 
	m=re.match(r"B|W",str)
 
	if m is None: return -1
 
	return m.end()
 
	
 
def simpleText(str):
 
	res=r""
 
	esc=False
 
	for c in str:
 
		if esc:
 
			res+=c
 
			esc=False
 
		elif c=="\\":
 
			esc=True
 
		elif c=="]":
 
			break
 
		else:
 
			res+=c
 
	return res"""
 
 
# TODO:
 
# date
 
 
 
"""
 
# move
 
B	move
 
KO	none
 
MN	number
 
W	move
 
 
# setup
 
AB	list of stone
 
AE	list of point
 
AW	list of stone
 
PL	color
 
 
# node annotation
 
C	text
 
DM	double
 
GB	double
 
GW	double
 
HO	double
 
N	simpleText
 
UC	double
 
V	real
 
 
# move annotation
 
BM	double

Changeset was too big and was cut off... Show full diff anyway

0 comments (0 inline, 0 general)