Files
@ 686166c7d5bc
Branch filter:
Location: Diana/src/diana/sgfParser/node.py
686166c7d5bc
3.2 KiB
text/x-python
added more whitespace
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 121 122 123 124 125 126 127 | 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
# check value type
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 beautiful 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)+"\n")
childCount = len(node.children)
if childCount == 0: # a leaf
output.append(")"*right+"\n")
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(list(children)))
return "".join(output)
|