diff --git a/sgfParser.py b/sgfParser.py --- a/sgfParser.py +++ b/sgfParser.py @@ -1,434 +1,434 @@ import re - + 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) - + nodes=[] + 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) + + 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 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) - - 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 - + 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) + + 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 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()) + 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)) + 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) - } + 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 + # 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() + 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 + i=cValueType(str[1:]) + if str[0]=="[" and i>=0 and str[i]=="]": return i+1 + else: return -1 class propValue: - pass + 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 + 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) + 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() + 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() - + 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() - + 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""" + 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()