Files
@ fdd10bc51cf8
Branch filter:
Location: Diana/src/diana/sgfParser/node.py
fdd10bc51cf8
3.0 KiB
text/x-python
optional background color
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | from collections import deque
import logging as log
from . import skipWhitespace, ParserWarning
from .property import Property, GAME_INFO
class Node:
def __init__(self):
self.properties=dict()
self.parent=None
self.children=[]
@staticmethod
def fits(s,i):
return i<len(s) and s[i]==";"
@staticmethod
def create(s,start):
assert Node.fits(s,start)
res=Node()
i=skipWhitespace(s,start+1)
while Property.fits(s,i):
i,x=Property.create(s,i)
if x.name in res.properties:
log.warning(ParserWarning('duplicate "{0}" property in a node. second value ignored'.format(x.name),s,i))
else:
res.properties[x.name]=x
i=skipWhitespace(s,i)
return (i,res)
def listGINodes(self):
if self.isGINode(): yield self
empty=not self.isGINode()
node=self
while node.parent:
node=node.parent
if node.isGINode():
empty=False
yield node
queue=deque(self.children)
while len(queue)>0:
node=queue.popleft()
if node.isGINode():
empty=False
yield node
queue.extend(node.children)
if empty: yield self # always yield at least self, can work as GINode as well as any other
def isGINode(self):
return any(prop.type==GAME_INFO for prop in self.properties.values())
def setProp(self,name,value):
self.properties[name]=value
# zkontrolovat typ value
def setChildren(self,children):
self.children=children
for child in children: child.parent=self
def addChild(self,node):
if node in self.children: return node
node.parent=self
self.children.append(node)
return node
def removeChild(self,node):
if node not in self.children:
return None
del self.children[self.children.index(node)]
node.parent=None
return node
def removeChildAt(self,i):
if -len(self.children)<i<len(self.children):
res=self.children[i]
del self.children[i]
res.parent=None
return res
return None
## Create a copy of the Node, with the same parent and deep copied properties, no copied children.
def copy(self):
res=Node()
res.properties={k: v.copy() for (k,v) in self.properties.items()}
res.parent=self.parent
return res
def getProp(self,name,default=None):
if name in self.properties: return self.properties[name].value
else: return default
## Returns textual representation of the Node itself, but disregards its children.
def __str__(self):
return ";" + "".join(str(p) for p in self.properties.values())
def export(self):
# there is a beatiful recursive solution, which this stack is too narrow to contain
stack=[(self,1,1)]
output=[]
while len(stack)>0:
node,left,right=stack.pop()
if left>0: output.append("("*left)
output.append(str(node))
childCount=len(node.children)
if childCount==0: # a leaf
output.append(")"*right)
elif childCount==1: # a line
stack.append((node.children[0],0,right))
else: # a branching node
# first child pops first, last child closes parent's parentheses
children=zip(node.children,[1]*childCount,[1]*(childCount-1)+[1+right])
stack.extend(reversed(children))
return "".join(output)
|