import re # def digit(str): # if re.match("") str[0] def skipWhitespace(str,start): i=start while 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 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)) else: res.properties[x.name]=x i=skipWhitespace(str,i) i,x=Property.create(str,i) return (i,res) class Property: name="" value="" 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) 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 patterns=dict() 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) 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) } """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""" sgf=open("in/1-Hora-Simara.sgf").read() x=Collection(sgf) # 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 DO none IT none TE double # markup AR list of composed point:point CR list of point DD elist of point LB list of composed point:simpleText LN list of composed point:point MA list of point SL list of point SQ list of point TR list of point # root AP composed simpleText:simpleText CA simpleText FF number GM number ST number SZ number | composed number:number # game info AN simpleText BR simpleText BT simpleText CP simpleText DT simpleText EV simpleText GN simpleText GC text ON simpleText OT simpleText PB simpleText PC simpleText PW simpleText RE simpleText RO simpleText RU simpleText SO simpleText TM real US simpleText WR simpleText WT simpleText # timing BL real OB number OW number WL real # misc FG none | composition of number:simpleText PM number VW elist of point """